Является ли instanceof плохой практикой? Если да, то при каких обстоятельствах это еще предпочтительнее?
На протяжении многих лет я старался избегать instanceof
, когда это возможно. Используя полиморфизм или шаблон посетителя, где это применимо. Я полагаю, это просто облегчает обслуживание в некоторых ситуациях... Есть ли другие недостатки, о которых следует знать?
Я все же вижу его здесь и там в библиотеках Java, поэтому, полагаю, у него есть свое место? При каких обстоятельствах это предпочтительнее? Всегда ли это неизбежно?
Ответы
Ответ 1
Я могу представить некоторые случаи, например, у вас есть некоторые объекты библиотеки, которые вы не можете продлить (или было бы неудобно делать это), возможно, смешанные с некоторыми объектами вашего, все с одним базовым классом, вместе в сборнике.
Я полагаю, что в этом случае полезно использовать instanceof для различения некоторой обработки на этих объектах.
Идем в некотором обслуживании устаревшего кода, где вы не можете вводить какое-то новое поведение в много старых классов, просто добавляя новую небольшую функцию или исправление ошибки...
Ответ 2
Он определенно имеет свое место в реализации запаса equals
. Например.
public boolean equals ( Object o )
{
if ( this == o )
{
return true;
}
if ( ! (o instanceof MyClass) )
{
return false;
}
// Compare fields
...
}
Одна из опрятных вещей, которые нужно знать о instanceof, заключается в том, что ее LHS может быть null
, и в этом случае выражение оценивается как false
.
Ответ 3
Я думаю, что когда вам абсолютно нужно знать тип объекта, instanceof
- лучший вариант.
Плохая практика состояла бы в том, чтобы иметь много instanceof
s, один рядом друг с другом, и, согласно им, вызывают разные методы объектов (конечно же, кастинг).
Вероятно, это отразится на том, что иерархия нуждается в переосмыслении и, вероятно, рефакторинге.
Ответ 4
Когда вы находитесь в чистой OO-модели, тогда instanceof
определенно является запахом кода.
Если, однако, вы не используете 100% OO-модель или вам нужно вводить в нее материал снаружи, то instanceof или эквиваленты (isXXX()
, getType()
,...) могут иметь свои применения.
Общим "правилом" было бы избегать его, когда это возможно, особенно когда вы контролируете иерархию типов и можете использовать, например, политип подтипа. Идея состоит в том, чтобы не задавать объекту, какой тип он есть, и что-то делать с ним, а скорее прямо или косвенно запрашивать объект через посетителя (по существу, двойной полиморфизм) для выполнения некоторых действий.
Ответ 5
Его можно использовать как проверку здравомыслия перед литьем; в дополнение к проверке того, что ваш объект имеет правильный тип, он также проверяет, что он не является нулевым.
if (o instanceof MyThing) {
((MyThing) o).doSomething(); // This is now guaranteed to work.
} else {
// Do something else, but don't crash onto ClassCast- or NullPointerException.
}
Ответ 6
Я изучал эту же тему для других целей, и я нашел следующие ссылки действительно хорошими.
Ответ 7
Я согласен, что это может иметь неприятный запах. Множество экземпляров, особенно в цепочке, если они блокированы, плохо пахнут.
Иногда он может вести себя так, как вы этого не ожидали... Что-то, что я однажды произошло:
Class B extends A
Class C extends A
B b = new B();
C c = new C();
b instanceof B -> true
b instanceof C -> true
c instanceof C -> true
c instanceof B -> true
(в моем случае это произошло из-за спящего режима, делающего объекты-прокси.... но просто случай, когда код dpending на instanceof является рискованным)
Ответ 8
Как насчет в случае создания factory?
например.
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();
}