J'ai une classe de base, Base
. Il a deux sous-classes, Sub1
et Sub2
. Chaque sous-classe a quelques méthodes supplémentaires. Par exemple, Sub1
a Sandwich makeASandwich(Ingredients... ingredients)
et Sub2
a boolean contactAliens(Frequency onFrequency)
.
Puisque ces méthodes prennent des paramètres différents et font des choses complètement différentes, elles sont complètement incompatibles et je ne peux pas simplement utiliser le polymorphisme pour résoudre ce problème.
Base
fournit la plupart des fonctionnalités, et j'ai une grande collection d' Base
objets. Cependant, tous les Base
objets sont soit un, Sub1
soit un Sub2
et parfois j'ai besoin de savoir qui ils sont.
Cela semble être une mauvaise idée de faire ce qui suit:
for (Base base : bases) {
if (base instanceof Sub1) {
((Sub1) base).makeASandwich(getRandomIngredients());
// ... etc.
} else { // must be Sub2
((Sub2) base).contactAliens(getFrequency());
// ... etc.
}
}
Donc, je suis venu avec une stratégie pour éviter cela sans casting. Base
a maintenant ces méthodes:
boolean isSub1();
Sub1 asSub1();
Sub2 asSub2();
Et bien sûr, Sub1
implémente ces méthodes comme
boolean isSub1() { return true; }
Sub1 asSub1(); { return this; }
Sub2 asSub2(); { throw new IllegalStateException(); }
Et les Sub2
met en œuvre dans le sens opposé.
Malheureusement, maintenant Sub1
et Sub2
ont ces méthodes dans leur propre API. Donc, je peux le faire, par exemple, sur 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 cette façon, si l'objet est connu pour être seulement un Base
, ces méthodes sont non dépréciées et peuvent être utilisées pour se "convertir" en un type différent afin que je puisse invoquer les méthodes de la sous-classe. Cela me semble élégant d’une certaine manière, mais d’un autre côté, j’abuse un peu des annotations obsolètes comme moyen de "supprimer" des méthodes d’une classe.
Puisqu'une Sub1
instance est vraiment une base, il est logique d'utiliser l'héritage plutôt que l'encapsulation. Est-ce que je fais bien? Existe-t-il un meilleur moyen de résoudre ce problème?
instanceof
, d'une manière qui nécessite beaucoup de dactylographie, est source d'erreurs et rend difficile l'ajout de plusieurs sous-classes.
Sub1
et Sub2
ne peuvent pas être utilisés de manière interchangeable, alors pourquoi les traitez-vous comme tels? Pourquoi ne pas garder une trace de vos "sandwich-makers" et de vos "alien-contacters" séparément?