SOLID – Liskov Substitution

Le “L” de SOLID, la troisième lettre qui correspond au principe de substitution de Liskov. Pourquoi ce nom ? Car il nous vient de Barbara Liskov et de Jeannette Wing. Mais alors, qu’en est-il ? Voyons voir la définition :

Principe de substitution
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.

Compliqué ? Il faut avouer qu’il n’y a rien de mieux qu’une analogie pour comprendre ce genre de choses alors nous allons parler géométrie. Il est facile de dire qu’un carré est un rectangle. La nuance est faite uniquement par le carré car celui-ci détient 4 côtés de même longueur. En revanche, rien ne l’empêche d’être un rectangle car ils ont bien tous les 2, 4 angles droits.

Maintenant, plaçons-nous d’un point de vue objet. Si l’on suit rigoureusement le principe d’héritage dans la programmation objet qui se base sur la formule : “est un”, il est tout à fait envisageable d’avoir un objet Carré qui hérite de la classe Rectangle. “Un carré est un rectangle”. Et bien grâce à Barbara, elle nous indique que nous sommes en erreur ! Revoyons pourquoi en reprenant la notion de substituabilité :

La substituabilité

Si S est un sous-type de T, alors tout objet de type T peut être remplacé par un objet de type S sans altérer les propriétés désirables du programme concerné.

Donc! Conceptuellement, si un Carré est un sous-type d’un Rectangle, alors on peut remplacer un Carré par un Rectangle sans que le programme concerné parte en sucette. FAUX ! Voyons plutôt avec du code :

Vous voyez le problème ? J’entends certains me dire : “Tu nous racontes que dans l’Open / Close, on peut étendre et améliorer nos objets pour ne pas les modifier et là, tu n’es pas content”. Et bien oui, on doit bien respecter ce principe d’open / close mais il faut penser à prendre en compte le fonctionnement initial d’un objet.

Lorsque vous modifiez la largeur d’un rectangle, on ne touche que sa largeur (x2). De même pour sa longueur (x2). Or lorsque vous devez modifier la largeur ou la longueur d’un carré… qu’importe, tout le monde doit avoir la même valeur. Dans le cas ce cet héritage, vous êtes dans l’obligation de modifier les deux “setters” pour être certains d’avoir les mêmes valeurs en permanence. Cependant, ce sont les fondamentaux du Rectangle que vous êtes en train de modifier. Si vous devez modifier l’un des fondamentaux, alors le Carré n’est plus un Rectangle. Conceptuellement parlant, ce n’est pas correct. Vous êtes en train d’altérer les propriétés initiales pour faire en sorte que votre système fonctionne. La réalité, c’est qu’un objet Carré est d’ailleurs bien plus simple :

Finalement… pas besoin d’héritage 🙂 Pour un Carré, vous n’avez besoin de gérer qu’un seul côté puisque les 4 sont les mêmes ! Alors attention 😉 Même si vous avez la possibilité de dire “est un“, l’héritage n’est pas automatique ! #LesAntibiotiques.