Использование ключевого слова instanceof

Использует ключевое слово instanceof для сущности object oriented programming? Я имею в виду, это плохая практика программирования? Я где-то читал, что использование ключевого слова instanceof означает, что дизайн может быть не таким уж хорошим. Любой лучший способ обхода?

Ответ 1

В общем, да. Лучше всего сохранить весь код, зависящий от того, чтобы быть определенным классом в этом классе, а использование instanceof обычно означает, что вы внесли некоторый код вне этого класса.

Посмотрите на этот очень простой пример:

public class Animal
{
}

public class Dog extends Animal
{
}

public class Cat extends Animal
{
}

public class SomeOtherClass
{
  public abstract String speak(Animal a)
  {
    String word = "";

    if (a instanceof Dog)
    {
      word = "woof";
    }
    else if (a instanceof Cat)
    {
      word = "miaow";
    }

    return word;
  }
}

В идеале мы хотели бы, чтобы все поведение, характерное для собак, содержалось в классе Dog, а не распространялось по нашей программе. Мы можем изменить это, переписав нашу программу следующим образом:

public abstract class Animal
{
  public String speak();
}

public class Dog extends Animal
{
  public String speak()
  {
    return "woof";
  }
}

public class Cat extends Animal
{
  public String speak()
  {
    return "miaow";
  }
}

public class SomeOtherClass
{
  public String speak(Animal a)
  {
    return a.speak();
  }
}

Мы указали, что Animal должен иметь метод speak. Теперь SomeOtherClass не нужно знать конкретные детали каждого типа животных - это может передать это подклассу Animal.

Ответ 2

Есть много хороших ответов, способствующих виртуальным методам, но instanceof также использует его. Представьте, что вы перебираете List<Event>, чтобы забрать все объекты Urgent. Вы можете сделать это с помощью isUrgent(), но я не уверен, что он был бы более кратким или читаемым. Кроме того, isUrgent() потребовало бы, чтобы Event знал, что его подклассы могут обладать соответствующим свойством, которое может:

следует рассматривать как нечто против принципов модульности; быть даже невозможным, если Event принадлежит к некоторой библиотеке, которая не может быть изменена.

Ответ 3

Благоприятный полиморфизм и динамическое связывание с downcasting и instanceof. Это "OO Way" и позволяет вам писать код, который не должен знать о подтипах.

Пример

abstract class Animal {
    public abstract void talk();
    //...
}

class Dog extends Animal {
    public void talk() {
        System.out.println("Woof!");
    }
    //...
}

class Cat extends Animal {
    public void talk() {
        System.out.println("Meow!");
    }
    //...
}

class Hippopotamus extends Animal {
    public void talk() {
        System.out.println("Roar!");
    }
    //...
}

class Main {

    public static void main(String[] args) {

        makeItTalk(new Cat());
        makeItTalk(new Dog());
        makeItTalk(new Hippopotamus());
    }

    public static void makeItTalk(Animal animal) {

        animal.talk();
    }
}

Ответ 4

Использование instanceof обескураживается, когда тот же эффект может быть достигнут с помощью виртуальных методов, например, в примере thomson_matt. Однако в некоторых случаях необходимо использовать instanceof. Например, когда ваш код получает объект из внешнего источника, скажем, сетевого или стороннего API, который возвращает Object, и вы должны решить, какой тип этого объекта и действовать соответствующим образом.

Ответ 5

Ключ должен не видеть instanceof как часть обычной "обычной практики". Как и интроспекция в целом, instanceof является специальным инструментом для использования, в частности, нетипичными обстоятельствами. Всякий раз, когда вы используете "instanceof", вы также можете использовать другие "специальные" части платформы, такие как отражение в целом.

До тех пор, пока всякий раз, когда вы его используете, вы соглашаетесь с тем, что то, что вы делаете, - это kludge в отсутствие более элегантной/практической альтернативы, а затем это хорошо.

Тем не менее, наиболее типичными обстоятельствами повседневных программ являются:

  • реализация equals()
  • чтение сериализованных объектов
  • несколько других случаев, когда вам предоставляется массив/коллекция элементов, например. перечисление JComponents в фрейме/контейнере и последующее действие в зависимости от типа.

Правило большого пальца, на которое вы можете попытаться придерживаться, - не требовать от пользователей библиотеки использовать "экземпляр", а скорее иметь любые случаи "instanceof", внутренние для библиотеки.

Или иначе, вы должны переформулировать свой вопрос: "Каковы случаи, когда" intsanceof "является обходным способом?"

Ответ 6

Это обескуражило, потому что люди могли использовать его, чтобы сделать что-то вроде этого:

if( myAnimal instanceof Dog )
    ((Dog)myAnimal).bark();
else( myAnimal instanceof Cat )
    ((Cat)myAnimal).meow();

Вместо этого Animal должен иметь метод speak(), который наследует Dog и Cat. В правильном ООП с полиморфизмом и динамическим связыванием вы просто делаете

myAnimal.speak();

Однако существуют некоторые экземпляры, в которых вы должны использовать instanceof для определения конкретного типа объекта. Возможно, у вас есть список Animals в вашем доме, и единственными, которые вы хотите вынести для walk(), являются Dog s. В этом случае вы будете проходить через ваш список и только walk() собак.

Ответ 7

Как насчет в случае создания factory (см. ниже)? В этом случае я не думаю, что подкласс Animal подходит для того, чтобы знать, как построить клетку для себя. Похоже, что вне сферы действия того, что такое Animal, и заставляет подкласс Animal брать на себя поведение, которое не является неотъемлемой частью того, что есть Animal.

public static Cage createCage(Animal animal) {
  if (animal instanceof Dog)
    return new DogHouse();
  else if (animal instanceof Lion)
    return new SteelCage();
  else if (animal instanceof Chicken)
    return new ChickenWiredCage();
  else if (animal instanceof AlienPreditor)
    return new ForceFieldCage();
  ...
  else
    return new GenericCage();
}

Ответ 8

Другим использованием операции instaceOf может быть обработка ошибок. Если у вас есть аналогичная обработка ошибок для исключений, и вы хотите иметь все это в одном месте, вы можете использовать:

public void handleError(Throwable t, HttpServletRequest req) {
   if (t instaceOf ValidationException) {
              ...doSomewthing......
   } else    if (t instaceOf DataException) {
              ...doSomewthing......
   } else    if (t instaceOf DataException) {
              ...doSomewthing......
   } else {
              ...doSomewthing......
   }

}

с кодом выше, вы избежите иметь много

} catch <Exception> {

и вместо этого имеет только один

} catch (Throwable t) {
   handleError(t, request);
   return "errorPage" or whateveryouwant;
}

Кроме того, еще одна вещь: вы проверяете исходный код java, вы найдете так много обычаев instaceof.

И одна хорошая ссылка: статья об использовании instaceof