Je sais que Java ne prend pas en charge l'héritage multiple. Mais si je dois concevoir un système de classes pour, disons, le règne animal. Comment représenter les animaux qui sont des hybrides de deux animaux différents ? Par exemple, une mule (âne ou cheval ?), un ligre (lion ou tigre). Comment hériter des classes Lion et Tigre pour créer une classe Liger ? Existe-t-il un moyen de le faire sans faire de Tiger et de Lion des interfaces ? Que se passe-t-il s'il est impossible de les transformer en interfaces ?
Réponses
Trop de publicités?L'héritage n'est pas le bon outil à utiliser dans ce cas. En effet, un ligre est pas un tigre, et ni l'un ni l'autre n'est un lion. Il a caractéristiques des deux, mais il est ni l'un ni l'autre.
Imaginons que vous alliez dans un zoo et que la cage indique "Tigre". Vous jetez un coup d'œil à l'intérieur et vous voyez un chat gigantesque et bizarre que vous ne reconnaissez certainement pas comme un tigre. C'est cool mais pas un tigre. Vous ne pensez pas non plus que c'est un lion. Ce n'est pas substituable pour l'un ou l'autre.
Il devrait donc composer a Lion
et un Tiger
y délégué son comportement vers le bon, ou de "passer outre" leurs comportements, totalement ou partiellement.
UPDATE :
Maintenant, que faire si vous voulez vraiment une sorte d'héritage multiple, comme si vous vouliez dériver un Liger
à la fois d'un Hybrid
et un Feline
? Jetez un coup d'œil à Traits Scala pour une possibilité. Pour la mettre en œuvre en Java, il vous faudrait une interface et une classe pour chaque concept de la conception dont vous voulez multiplier les "héritages". Jetez un coup d'œil aquí pour l'idée.
Ils auront toujours besoin d'être des interfaces si vous souhaitez qu'un même objet puisse être identifié comme étant les deux.
Vous pouvez souvent déléguer le comportement à des classes composées, mais dans le cas du ligre (c'est ma sous-classe préférée), vous devez décider quel comportement de l'animal aura la priorité. Un ligre peut être un descendant direct de l'un ou de l'autre, ou d'aucun des deux.
Java n'autorise que l'héritage d'API multiples (interfaces), pas l'implémentation.
Java ne prend pas en charge l'héritage de classes multiples. Considérez les fonctions que "Lion" et "Tigre" pourraient avoir en commun. Java n'a pas voulu résoudre le problème de la "collision de fonctions" :
class Lion{
public String call(){
return "ROAR";
}
}
class Tiger{
public String call(){
return "growl";
}
}
class Liger extends Lion, Tiger{
}
public static void main(String[] args){
System.out.println(new Liger().call());
}
Que faut-il imprimer ?
Java ne prend pas en charge l'héritage de classes multiples, donc cela ne fonctionne pas - la partie "extends Lion, Tiger" de la déclaration de classe est illégale. Java prend en charge un mécanisme de désambiguïsation pour les interfaces, mais cela n'a pas été étendu aux classes.
La meilleure solution consiste à convertir tous La classe animale est transformée en interface, puis le code est converti en implémentations de ces interfaces. Un Liger pourrait être implémenté comme suit :
interface Liger extends Lion, Tiger { }
class LigerImpl implements Liger{
private Lion mom;
private Tiger dad;
public LigerImpl(){
mom = new LionImpl();
dad = new TigerImpl();
}
public String call(){
if(math.random() > 0.5){
return mom.call();
} else {
return dad.call();
}
}
Cette approche nécessite une délégation explicite à chacune des implémentations sous-jacentes ; absolument rien ne se produit "gratuitement". Java ne vous rapprochera pas plus de cette approche. La conception de Java se résume à peu près à "si quelque chose est d'une manière ou d'une autre ambigu, dangereux, indéfini, ou pourrait potentiellement causer un conflit de type ou d'analyse, faites en sorte que le programmeur écrive plus de code".
Je suis PAS Je ne vous recommande pas de le faire, mais la réflexion pourrait fonctionner. Bien sûr, l'utilisation de "instanceof" ne fonctionnera jamais...
public class Lion {
public void roar() {
System.out.println("Lion is roaring");
}
public void eat(String what) {
System.out.println("Lion is eating " + what);
}
}
public class Tiger {
public void purr() {
System.out.println("Tiger is purring");
}
public void eat(String what) {
System.out.println("Tiger is eating " + what);
}
}
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Liger {
public static void main(String[] args) {
Liger liger = new Liger();
liger.purr();
liger.roar();
liger.eat("food");
//Result
//Tiger is purring
//Lion is roaring
//Tiger is eating food
//Lion is eating food
}
private ArrayList<Object> _extends = new ArrayList<Object>();
public Liger() {
_extends.add(new Tiger());
_extends.add(new Lion());
}
private void invoke(String methodName, Object... args) {
for ( Object obj : _extends ) {
Class cls = obj.getClass();
Method[] methods = cls.getMethods();
for ( Method m : methods ) {
if ( m.getName().equals(methodName) ) {
try {
m.invoke(obj, args);
}
catch ( Exception ex ) {
//handle me
}
continue;
}
}
}
}
public void purr() {
invoke("purr"); //Tiger only
}
public void roar() {
invoke("roar"); // Lion only
}
public void eat(String what) {
invoke("eat", what); //Both
}
}