Principe de substitution
Nous avons vu différents types d'abstraction, et nous allons nous intéresser à l'abstraction par hiérarchie de type, qui est un des piliers des concepts de l'orienté-objet.
Hiérarchie de classe, héritage
En orienté-objet, l'héritage permet par exemple de définir des comportements minimum pour une classe, et d'ajouter les comportements spécifiques dans des classes enfants, qui héritent (dérivent) de la classe parent.
Parmi les avantages de cette manière de programmer, nous pouvons retenir qu'il n'est plus nécessaire de re-définir dans les classes enfants ce qui est déjà défini dans les classes parents. Ceci nous permet une abstraction par hiérarchie de type, c'est à dire que nous pouvons considérer les différents enfants comme étant du type parent.
Un des exemple souvent utilisé pour expliquer l'héritage est issu de la géométrie :
- Un quadrilatère possède 4 côtés
- Un parallélogramme possède aussi 4 côtés, c'est un quadrilatère.
Il est cependant particulier, car il possède en plus la particularité d'avoir des côtés opposés de même longueur.- Un rectangle possède aussi 4 côtés et des côtés opposés de même longueur, c'est un quadrilatère, et même un parallélogramme.
Il est cependant particulier, car il possède en plus la particularité d'avoir 4 angles droits.- Un carré possède toutes les caractéristiques d'un rectangle, c'est donc un rectangle.
Il est cependant particulier, car il possède en plus la particularité d'avoir 4 côtés de même longueur.
- Un carré possède toutes les caractéristiques d'un rectangle, c'est donc un rectangle.
- Un rectangle possède aussi 4 côtés et des côtés opposés de même longueur, c'est un quadrilatère, et même un parallélogramme.
- Un parallélogramme possède aussi 4 côtés, c'est un quadrilatère.
Ce type de classement est tout à fait correct au niveau de la sémantique et selon le point de vue de la géométrie, et naturellement c'est de cette manière que nous construisons notre hiérarchie de classes en programmation.
Cependant, Liskov soulève un problème au niveau du comportement attendu, car notre structure renforce à chaque fois les contraintes nécessaires à la création d'une forme par rapport à sa forme parent.
Principe de substitution, en bref
“Let q(x) be a property provable about objects x of type T. Then q(y) should be true for objects y of type S where S is a subtype of T.”
« Si q(x) est une propriété démontrable pour tout objet x de type T, alors q(y) est vraie pour tout objet y de type S tel que S est un sous-type de T. »
Barbara Liskov2et Jeannette Wing3Sémantique et substitution de Liskov
La sémantique nous pousse à utiliser une hiérarchie comme nous l'avons vu dans notre exemple du carré qui hérite des propriétés du rectangle, ce qui est logique car un carré est au moins un rectangle.
Cependant, si nous définissons dans la classe rectangle les méthodes suivantes affecteLargeur(entier largeur), affecteHauteur(entier hauteur), et entier donneSurface(), la méthode de calcul de la surface renvera la largeur multipliée par la hauteur. C'est correct.
Selon Liskov, le carré doit pouvoir à tout moment se comporter comme un rectangle. Notre exemple semble fonctionner correctement, voyons un cas pratique...
- L'utilisateur crée un rectangle r et carré c.
- Il décide de leur affecter une largeur égale à 2. Le carré, sachant que ses 4 côtés sont égaux, en profite pour affecter une hauteur identique.
- Il décide ensuite de leur affecter une hauteur égale à 3. Le carré, sachant que ses 4 côtés sont égaux, en profite pour affecter une largeur identique.
- L'utilisateur demande ensuite la surface du rectangle, et la méthode lui renvoie 6, ce qui est correct.
- Il demande ensuite la surface du carré, et selon Liskov le résultat attendu est identique à celui du rectangle (6). Cependant, le résultat pour le carré est différent (9).
Que s'est-il passé ? La méthode donne surface s'est comportée exactement de la méme manière pour le carré que pour le rectangle (largeur*hauteur), mais nous violons le principe de substitution de Liskov à chaque fois que nous affectons une valeur pour la largeur ou la hauteur du carré, car cela provoque un résultat différent.
Pourtant nous sommes obligés dans les affectations du carré d'afecter la méme valeur à la largeur et à la hauteur, sinon nous ne respectons plus la sémantique du carré.
Héritage et substitution de Liskov
Un des moyens de respecter les principes de substitutions de Liskov est d'inverser notre conçeption habituelle de l'héritage, et de coder un rectangle qui hérite d'un carré.
Proposition de solution
Nous pouvons donc utiliser la solution suivante : comme notre carré ne peut pas produire le résultat attendu sur un rectangle, nous ne définirons pas le carré comme héritant du rectangle, mais tous deux sont au même niveau, héritant du quadrilatère.
« Heu... Comment je fais si je veux mettre ensemble les carrés et les rectangles ? »
Comme le carré et le rectangle possèdent des caractéristiques communes que ne partagent pas les autres quadrilatères (4 angles droits), nous pouvons dire que le carré et le rectangle implémentent l'interface "QuatreAnglesDroits".
Par exemple en Java, si nous demandons sur notre objet qui est de type réel carré ou rectangle s'il est une instance de "Quadrilatère", il nous répondra "oui", et de la même manière si nous lui demandons s'il est une instance de "QuatreAnglesDroits" il nous répondra aussi "oui".
Spécifications et substitution de Liskov
L'abstraction par spécifications nous donne quelques pistes pour respecter le principe de substitution de Liskov :
- La clause REQUIRES dans le sous-type doit être égale ou inférieure à celle du type parent : affaiblissement des pré-conditions.
- La clause EFFECTS dans le sous-type doit produire au moins le même résultat que celle du type parent : renforcement des post-conditions.
Remarque
Même si je n'adhère pas toujours aux propos de Barbara Liskov4, les principes de substitution de Liskov soulèvent certaines questions intéressantes, et nous sensibilisent à certains dangers dans notre pratique de l'orienté-objet.
Nous devons avoir conscience du problème, mais nous utilisons souvent les principes d'héritage sans modifier le comportement des sous-classes, ce qui est sans danger.
Je n'ai pas le temps pour l'instant de détailler plus le sujet, mais il mérite que l'on s'y attarde, et je le ferais par la suite.
Nederlandse vertaling
U hebt gevraagd om deze site in het Nederlands te bezoeken. Voor nu wordt alleen de interface vertaald, maar nog niet alle inhoud.Als je me wilt helpen met vertalingen, is je bijdrage welkom. Het enige dat u hoeft te doen, is u op de site registreren en mij een bericht sturen waarin u wordt gevraagd om u toe te voegen aan de groep vertalers, zodat u de gewenste pagina's kunt vertalen. Een link onderaan elke vertaalde pagina geeft aan dat u de vertaler bent en heeft een link naar uw profiel.
Bij voorbaat dank.
Document heeft de 03/01/2010 gemaakt, de laatste keer de 26/10/2018 gewijzigd
Bron van het afgedrukte document:https://www.gaudry.be/nl/oriente-objet-principe-substitution.html
De infobrol is een persoonlijke site waarvan de inhoud uitsluitend mijn verantwoordelijkheid is. De tekst is beschikbaar onder CreativeCommons-licentie (BY-NC-SA). Meer info op de gebruiksvoorwaarden en de auteur.
- ↑ Barbara Liskov : Barbara Liskov (7-11-1939) est professeur au MIT [Massachusetts Institute of Technology] au département Engineering's Electrical Engineering and Computer Science.
- ↑ Jeannette M. Wing : Jeannette M. Wing, a fait ses études au MIT [Massachusetts Institute of Technology], et est professeur d'informatique à l'Université Carnegie Mellon. Elle est directrice du département d'informatique.
- ↑ Liskov et equals : Barbara Liskov considère que l'implémentation de la méthode equals retourne true, pour des objets mutables, uniquement lors d'une égalité de pointeur (l'opérateur ==). Son argumentation est tout à fait justifiée, mais sa solution n'est absolument pas acceptable, car Java se base sur cette méthode (parfois en corrélation avec hashCode) pour l'égalité de deux objets au niveau de la logique métier, par exemple dans les collections.
Referenties
- La maîtrise du développement du logiciel : abstraction et spécification : Barbara Liskov et John V. Guttag (1990)
- The Liskov Substitution Principle : T. S. Norvell (2003)
Deze verwijzingen en links verwijzen naar documenten die geraadpleegd zijn tijdens het schrijven van deze pagina, of die aanvullende informatie kunnen geven, maar de auteurs van deze bronnen kunnen niet verantwoordelijk worden gehouden voor de inhoud van deze pagina.
De auteur Deze site is als enige verantwoordelijk voor de manier waarop de verschillende concepten, en de vrijheden die met de referentiewerken worden genomen, hier worden gepresenteerd. Vergeet niet dat u meerdere broninformatie moet doorgeven om het risico op fouten te verkleinen.