68 votes

Principe de substitution de Liskov - aucune méthode prioritaire / virtuelle?

Ma compréhension du principe de substitution de Liskov, c'est que certaines propriétés de la classe de base qui est vrai ou certaines mises en œuvre de comportement de la classe de base, devrait être vrai pour la classe dérivée ainsi.

Je suppose que cela signifie quand une méthode est définie dans une classe de base, il ne devrait jamais être surdéfini dans la classe dérivée - depuis la substitution de la classe de base au lieu de la classe dérivée donnerait des résultats différents. Je suppose que cela signifie, avoir (non-pur) méthodes virtuelles est une mauvaise chose?

Je pense que je pourrais avoir une mauvaise compréhension du principe. Si je ne le fais pas, je ne comprends pas pourquoi ce principe est-il une bonne pratique. Quelqu'un peut-il m'expliquer cela? Merci

67voto

dustmachine Points 4069

Les sous-classes de substitution des méthodes dans la classe de base sont totalement autorisés par le Liskov Substitution Principe.

Ce pourrait être la simplification de trop, mais je m'en souviens comme "une sous-classe doit exiger rien de plus et de promesse, rien de moins"

Si un client est à l'aide d'une superclasse ABC avec une méthode something(int i), alors le client doit être en mesure de remplacer une sous-classe de ABC sans problèmes. Au lieu de penser en termes de types de variables, peut-être y penser en termes de préconditions et postconditions.

Si notre something() méthode ABC classe de base ci-dessus a une atmosphère détendue condition préalable qui permet tout entier, toutes les sous-classes de ABC doit également permettre tout entier. Une sous-classe GreenABC n'est pas autorisé à ajouter une condition préalable à l' something() méthode qui nécessite le paramètre d'être positif entier. Ce serait violer le Principe de Substitution de Liskov (c'est à dire, exigeant plus). Donc, si un client est à l'aide de la sous-classe BlueABC et en passant des entiers négatifs à l' something() le client ne cassera pas si nous devons passer d' GreenABC.

A l'inverse, si la base ABC classe something() méthode a une postcondition - comme garantissant qu'il ne sera jamais retourner une valeur de zéro, alors tous les sous-classes doivent aussi obéir à la même postcondition ou qu'elles violent le Principe de Substitution de Liskov (c'est à dire, en promettant de moins).

J'espère que cette aide.

13voto

vibhu Points 581

Il est un exemple populaire qui dit que si il nage comme un canard, charlatan aime un canard, mais nécessite des piles, puis il se casse Principe de Substitution de Liskov.

Dit plus simplement, vous disposez d'une base de Canard de la classe, qui est utilisé par quelqu'un. Ensuite, vous ajoutez de la hiérarchie par l'introduction PlasticDuck avec le même remplacé les comportements (comme la natation, quacking etc.) comme un Canard, mais nécessite des piles de simuler les comportements. Essentiellement, cela signifie que vous sont en train d'introduire un supplément de pré-condition pour le comportement de la Sous-Classe nécessite des piles à faire le même comportement que l'on a précédemment fait par la Base de Canard de la classe sans piles. Cela pourrait prendre le consommateur de votre Canard de la classe par surprise et pourrait rompre la fonctionnalité construit autour du comportement attendu de la Base de Canard de la classe.

Voici un bon lien - http://lassala.net/2010/11/04/a-good-example-of-liskov-substitution-principle/

7voto

queen3 Points 8810

Non, il dit que vous devriez être en mesure d'utiliser la classe dérivée de la même façon que sa base. Il y a de nombreuses façons que vous pouvez surcharger une méthode sans rupture. Un exemple simple, GetHashCode() en C# est dans la base pour TOUTES les classes, et encore TOUS d'entre eux peuvent être utilisés comme "objet" pour calculer le code de hachage. Un exemple classique de la rupture de la règle, aussi loin que je me souvienne, est derivin Carré, de Rectangle, depuis Carrés peut pas avoir à la fois la Largeur et la Hauteur, parce que la définition d'un allait changer l'autre et ainsi il n'est plus conforme à l'Rectangle règles. Vous pouvez, cependant, ont encore de la Forme de base avec .GetSize() car TOUTES les formes peuvent le faire - et donc des dérivées de forme peut être substitué et utilisé comme Forme.

6voto

Vitalii Fedorenko Points 17469

Primordial pauses Principe de Substitution de Liskov si vous modifiez l'un comportement défini par une méthode de base. Ce qui signifie que:

  1. La plus faible pré-condition pour une enfant de la méthode ne devrait pas être plus fort que pour la méthode de base.
  2. Une postcondition de l'enfant de la méthode implique une postcondition pour l' méthode parent. Lorsqu'une postcondition est constitué par: a) de tous les côtés les effets provoqués par l'exécution de la méthode et b) le type et la valeur de retour de l'expression.

À partir de ces deux exigences, vous pouvez laisser supposer que de nouvelles fonctionnalités à un enfant de méthode qui n'a pas d'incidence sur ce qui est attendu d'une super méthode ne viole pas le principe. Ces conditions vous permettent d'utiliser une sous-classe de l'instance où une super-classe de l'instance est nécessaire.

Si ces règles ne sont pas obéi à une classe de viole de LSP. Un exemple classique est la hiérarchie suivante: classe Point(x,y), classe ColoredPoint(x,y,color) qui s'étend au - Point(x,y) et méthode substituée equals(obj) en ColoredPoint qui reflète l'égalité par la couleur. Maintenant, si on une instance de Set<Point> il peut supposer que les deux points avec les mêmes coordonnées sont égales dans cet ensemble. Ce qui n'est pas le cas avec la méthode de remplacement equals et, en général, il n'y a tout simplement aucun moyen d'étendre une classe instanciable et ajouter un aspect utilisés en equals méthode sans rupture de LSP.

Ainsi, chaque fois que vous briser ce principe vous implicitement introduire un bug potentiel qui révèle lors de l'invariant pour un parent de la classe qui est prévu par le code n'est pas satisfait. Cependant, dans le monde réel, souvent, il n'est pas évident de trouver la solution de conception qui ne viole pas LSP, de sorte que l'on peut utiliser, par exemple, @ViolatesLSP de la classe d'annotation pour avertir d'un client qu'il n'est pas sûr d'utiliser des instances de classe dans un ensemble polymorphe ou dans tout autre type de cas, qui s'appuient sur le principe de substitution de Liskov.

2voto

quamrana Points 6411

Je pense que vous êtes littéralement correcte dans la façon de décrire le principe et seulement primordial virtuelle pure, ou de méthodes abstraites fera en sorte que vous n'avez pas la violer.

Cependant, si vous regardez le principe à partir d'un point de vue des clients, c'est une méthode qui prend une référence à la classe de base. Si cette méthode ne peut pas dire (et ne pas essayer et ne pas avoir à le savoir), la classe de toute instance est passé, alors vous êtes aussi de ne pas violer le principe. Donc, il ne peut pas d'importance qui vous substituez une méthode de classe de base (des sortes de décorateurs pourrait le faire, l'appel de la méthode de classe de base dans le processus).

Si un client semble avoir besoin de trouver la classe d'une instance passée, alors vous êtes dedans pour un entretien cauchemar, que vous devriez vraiment être en ajoutant de nouvelles classes dans le cadre de votre effort de maintenance, pas de modification d'une routine. (voir aussi OCP)

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