Tengo una clase base, Base
. Tiene dos subclases Sub1
y Sub2
. Cada subclase tiene algunos métodos adicionales. Por ejemplo, Sub1
tiene Sandwich makeASandwich(Ingredients... ingredients)
y Sub2
tiene boolean contactAliens(Frequency onFrequency)
.
Dado que estos métodos toman parámetros diferentes y hacen cosas completamente diferentes, son completamente incompatibles, y no puedo usar el polimorfismo para resolver este problema.
Base
proporciona la mayor parte de la funcionalidad, y tengo una gran colección de Base
objetos. Sin embargo, todos los Base
objetos son a Sub1
o a Sub2
, y a veces necesito saber cuáles son.
Parece una mala idea hacer lo siguiente:
for (Base base : bases) {
if (base instanceof Sub1) {
((Sub1) base).makeASandwich(getRandomIngredients());
// ... etc.
} else { // must be Sub2
((Sub2) base).contactAliens(getFrequency());
// ... etc.
}
}
Así que se me ocurrió una estrategia para evitar esto sin lanzar. Base
ahora tiene estos métodos:
boolean isSub1();
Sub1 asSub1();
Sub2 asSub2();
Y, por supuesto, Sub1
implementa estos métodos como
boolean isSub1() { return true; }
Sub1 asSub1(); { return this; }
Sub2 asSub2(); { throw new IllegalStateException(); }
Y los Sub2
implementa de la manera opuesta.
Lamentablemente, ahora Sub1
y Sub2
tienen estos métodos en su propia API. Entonces puedo hacer esto, por ejemplo, en 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(); }
De esta manera, si se sabe que el objeto es solo a Base
, estos métodos no están en desuso y se pueden usar para "lanzarse" a un tipo diferente para que yo pueda invocar los métodos de la subclase. Esto me parece elegante de alguna manera, pero por otro lado, estoy abusando de las anotaciones obsoletas como una forma de "eliminar" métodos de una clase.
Dado que una Sub1
instancia realmente es una Base, tiene sentido usar la herencia en lugar de la encapsulación. ¿Lo que estoy haciendo bien? ¿Hay una mejor manera de resolver este problema?
instanceof
, de una manera que requiere mucho tipeo, es propenso a errores y dificulta agregar más subclases.
Sub1
y Sub2
no se pueden usar indistintamente, ¿por qué los trata como tal? ¿Por qué no realizar un seguimiento de sus 'fabricantes de sándwiches' y 'contactores alienígenas' por separado?