использование ключевого слова instanceof - PullRequest
10 голосов
/ 06 июля 2011

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

Ответы [ 8 ]

14 голосов
/ 06 июля 2011

Вообще говоря, да. Лучше сохранить весь код, который зависит от того, является ли он конкретным классом в этом классе, и использование 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.

4 голосов
/ 06 июля 2011

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

следует рассматривать как нечто, противоречащее принципам модульности; будет даже невозможно, если Event принадлежит какой-то библиотеке, которую нельзя изменить.
3 голосов
/ 07 июля 2011

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

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

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

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

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

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

3 голосов
/ 06 июля 2011

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

3 голосов
/ 06 июля 2011

Пользу полиморфизм и динамическое связывание с понижением и 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();
    }
}
2 голосов
/ 06 июля 2011

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

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() собак.

0 голосов
/ 01 декабря 2014

Еще одним применением операции 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

0 голосов
/ 08 ноября 2012

Как насчет создания фабрики (см. Ниже)? В этом случае я не думаю, что для подкласса 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();
}
...