У меня есть базовый класс Base
. У него есть два подкласса, Sub1
и Sub2
. Каждый подкласс имеет несколько дополнительных методов. Например, Sub1
имеет Sandwich makeASandwich(Ingredients... ingredients)
и Sub2
имеет boolean contactAliens(Frequency onFrequency)
.
Поскольку эти методы принимают разные параметры и делают совершенно разные вещи, они абсолютно несовместимы, и я не могу просто использовать полиморфизм для решения этой проблемы.
Base
обеспечивает большую часть функциональности, и у меня есть большая коллекция Base
объектов. Тем не менее, все Base
объекты либо a, Sub1
либо a Sub2
, и иногда мне нужно знать, какие они есть.
Кажется плохой идеей сделать следующее:
for (Base base : bases) {
if (base instanceof Sub1) {
((Sub1) base).makeASandwich(getRandomIngredients());
// ... etc.
} else { // must be Sub2
((Sub2) base).contactAliens(getFrequency());
// ... etc.
}
}
Поэтому я разработал стратегию, чтобы избежать этого без кастинга. Base
Теперь есть эти методы:
boolean isSub1();
Sub1 asSub1();
Sub2 asSub2();
И, конечно же, Sub1
реализует эти методы как
boolean isSub1() { return true; }
Sub1 asSub1(); { return this; }
Sub2 asSub2(); { throw new IllegalStateException(); }
И Sub2
реализует их противоположным образом.
К сожалению, сейчас Sub1
и Sub2
есть эти методы в собственном API. Так что я могу сделать это, например, на Sub1
.
/** no need to use this if object is known to be Sub1 */
@Deprecated
boolean isSub1() { return true; }
/** no need to use this if object is known to be Sub1 */
@Deprecated
Sub1 asSub1(); { return this; }
/** no need to use this if object is known to be Sub1 */
@Deprecated
Sub2 asSub2(); { throw new IllegalStateException(); }
Таким образом, если известно, что объект является только a Base
, эти методы не являются устаревшими и могут использоваться для «приведения» себя к другому типу, чтобы я мог вызывать методы подкласса для него. В некотором смысле это кажется мне элегантным, но, с другой стороны, я немного злоупотребляю устаревшими аннотациями как способом «удалить» методы из класса.
Поскольку Sub1
экземпляр действительно является Base, имеет смысл использовать наследование, а не инкапсуляцию. Что я делаю хорошо? Есть ли лучший способ решить эту проблему?
instanceof
, таким образом, требует много печатания, подвержено ошибкам и затрудняет добавление дополнительных подклассов.
Sub1
и Sub2
не могут быть использованы взаимозаменяемо, то почему вы относитесь к ним как таковой? Почему бы не отслеживать ваши «сэндвичницы» и «инопланетян» по отдельности?