Eu tenho uma classe base Base
,. Tem duas subclasses Sub1
e Sub2
. Cada subclasse possui alguns métodos adicionais. Por exemplo, Sub1
tem Sandwich makeASandwich(Ingredients... ingredients)
e Sub2
temboolean contactAliens(Frequency onFrequency)
.
Como esses métodos usam parâmetros diferentes e fazem coisas totalmente diferentes, eles são completamente incompatíveis, e não posso simplesmente usar o polimorfismo para resolver esse problema.
Base
fornece a maior parte da funcionalidade e tenho uma grande coleção de Base
objetos. No entanto, todos os Base
objetos são a Sub1
ou a Sub2
e, às vezes, preciso saber quais são.
Parece uma má idéia fazer o seguinte:
for (Base base : bases) {
if (base instanceof Sub1) {
((Sub1) base).makeASandwich(getRandomIngredients());
// ... etc.
} else { // must be Sub2
((Sub2) base).contactAliens(getFrequency());
// ... etc.
}
}
Então, criei uma estratégia para evitar isso sem vazamento. Base
agora possui estes métodos:
boolean isSub1();
Sub1 asSub1();
Sub2 asSub2();
E, é claro, Sub1
implementa esses métodos como
boolean isSub1() { return true; }
Sub1 asSub1(); { return this; }
Sub2 asSub2(); { throw new IllegalStateException(); }
E Sub2
implementa da maneira oposta.
Infelizmente, agora Sub1
e Sub2
tenha esses métodos em sua própria API. Então eu posso fazer isso, por exemplo 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(); }
Dessa forma, se o objeto é conhecido por ser apenas um Base
, esses métodos não são preteridos e podem ser usados para "converter" a si mesmo para um tipo diferente, para que eu possa invocar os métodos da subclasse. De certa forma, isso me parece elegante, mas, por outro lado, estou abusando das anotações obsoletas como uma maneira de "remover" os métodos de uma classe.
Como uma Sub1
instância realmente é uma Base, faz sentido usar herança em vez de encapsulamento. O que estou fazendo bem? Existe uma maneira melhor de resolver este problema?
instanceof
, de uma maneira que requer muita digitação, é propenso a erros e dificulta a adição de mais subclasses.
Sub1
e Sub2
não pode ser usado de forma intercambiável, por que você os trata como tal? Por que não acompanhar seus 'fabricantes de sanduíches' e 'alienígenas' separadamente?