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