2 votes

La covariance est-elle sûre ici ?

class Food{}

class Meat extends Food{}

class Animal{
    void feed(Food f){}
}

class Lion extends Animal{
    void feed(Meat m){}
}

void foo(Animal a){
   Food f = new Food();
   a.feed(f);
}

Que se passera-t-il si nous envoyons à foo(new Lion()) ? Je sais qu'il y aura une erreur mais j'ai besoin d'une explication s'il vous plaît.

5voto

Edwin Buck Points 33097

Votre Lion peut manger Meat mais il peut aussi manger n'importe quel type d'aliment (comme les épinards).

Si votre Lion ne pouvait manger aucune sorte de Food alors il ne peut pas être considéré comme une implémentation de Animal .

Il est essentiel de comprendre ce point lorsque l'on décide d'utiliser la sous-classe et l'héritage de classe comme moyen de construire des programmes : vous ne rendez pas vos sous-classes plus spécifiques que votre interface ou vos super-classes.

Pour que la sous-classification permette de résoudre des problèmes (au lieu d'en créer), vous devez respecter cette ligne directrice : All subclasses must be functionally equivalent to the super-class (Liskov Substitution Principle) Cela signifie que trois classes qui fournissent un accès à trois bases de données différentes sont un bon candidat pour être des sous-classes d'une classe commune (ou peut-être partager une interface commune), parce que la "fonctionnalité" est "offrir un accès à la base de données".

Où se trouve votre Lion l'exemple n'est pas à la hauteur, c'est que selon votre définition de la Animal dans le monde réel, les Lions ne sont pas une Animal parce que les Lions du monde réel ne mangent aucun type d'aliment. Food . Les Lions du monde réel sont plus spécifiques dans leur capacité à manger de la nourriture que la définition générale d'un animal inconnu. C'est cette différence fonctionnelle qui fait que la modélisation des Lions du monde réel en tant que sous-classes de cette définition spécifique de l'animal une mauvaise adaptation.

Vous pouvez facilement remédier à ce problème en faisant en sorte que l'élément Animal La méthode "manger de la nourriture" lance un IncompatibleFoodException qui modifie la définition d'un Animal de quelque chose qui "mange de la nourriture" à quelque chose qui "mange ou rejette de la nourriture".

2voto

Corbin Points 17420

Ceci est une violation de la Substitution de Liskov Il faut donc l'éviter (comme le dit Edwin, ce n'est pas vraiment un animal s'il ne peut pas manger de nourriture).

Contrairement à ce que l'on pourrait penser, cela n'entraînera pas d'erreur, mais appellera Animal::feed au lieu de Lion::feed comme prévu.

Je viens de relire le titre, et pour répondre spécifiquement à la question : Non, la covariance n'est pas sûre ici (en termes de comportement. En termes de syntaxe, elle l'est).

Copier-coller rapide de la question dans un exemple :

class Food{}

class Meat extends Food{}

class Animal{
    void feed(Food f){
        System.out.println("om nom nom");
    }
}

class Lion extends Animal{
    void feed(Meat m)
    {
        System.out.println("OM NOM NOM");
    }
}

public class test
{

    public static void main(String[] args)
    {
        foo(new Lion());
    }

    static void foo(Animal a){
       Food f = new Food();
       a.feed(f);
    }

}

Sortie "om nom nom"

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