3 votes

Conception de la hiérarchie des classes - héritage multiple en Java

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 ?

8voto

Jordão Points 29221

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.

6voto

Dave Newton Points 93112

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.

0voto

Bhesh Gurung Points 24875

Comme vous l'avez dit, c'est impossible. De plus, cela pourrait être le signe d'une mauvaise conception (car cela pourrait créer une ambiguïté même si c'était possible). Vous devriez donc essayer de l'éviter et de repenser votre conception.

0voto

Adam Norberg Points 2336

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".

0voto

maclema Points 5959

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
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X