Comprendre le Principe de Substitution de Liskov en Python : Un Guide Complet

Clean Code
Jan. 30, 2024
photo_elie
Auteur
Elie Terrien
Apprenez le principe de Substitution de Liskov (PSL) par l'exemple

Dans le domaine de la programmation orientée objet, le Principe de Substitution de Liskov (PSL) se présente comme un pilier fondamental, jouant un rôle crucial dans l'assurance de conceptions logicielles robustes et maintenables. Nommé d'après la scientifique en informatique Barbara Liskov, ce principe est intégral aux principes SOLID, un ensemble de directives visant à promouvoir des pratiques de codage évolutives, compréhensibles et flexibles. Cet article explore l'essence du PSL, offrant des aperçus de son application pratique dans la programmation Python.

Qu'est-ce que le Principe de Substitution de Liskov ?

Le PSL affirme que les objets d'une superclasse doivent pouvoir être remplacés par des objets de ses sous-classes sans affecter la correction du programme. En termes plus simples, si la classe B est une sous-classe de la classe A, alors partout où la classe A est utilisée, la classe B devrait pouvoir servir de substitut sans introduire d'erreurs ou de comportements inattendus.

Le principe ne concerne pas seulement les signatures de méthodes et les types de retour, mais aussi le fait de garantir que la sous-classe maintient le comportement attendu par la superclasse. Il s'agit d'adhérer au contrat établi par la superclasse.

Pourquoi le Principe de Substitution de Liskov est-il Important ?

L'importance du PSL réside dans sa capacité à garantir qu'un système logiciel reste facile à comprendre et à modifier. En adhérant au PSL, les développeurs peuvent :

Améliorer la Réutilisabilité du Code : S'assurer que les sous-classes restent fidèles au comportement de leurs classes parentes les rend plus polyvalentes et réutilisables.

Améliorer la Maintenabilité du Code : Le code conforme au PSL est généralement plus propre et mieux organisé, le rendant plus facile à maintenir et à étendre.

Réduire les Bugs et les Erreurs : En maintenant un comportement cohérent à travers une hiérarchie de classes, le PSL aide à éviter les bugs qui peuvent survenir du comportement inattendu des sous-classes.

Le PSL en Python : Un Guide Pratique

Exemple de Code Python Violant le PSL

Voici un exemple de code Python illustrant une violation du Principe de Substitution de Liskov (PSL) :

class Bird:
    def fly(self):
        return "I can fly!"

class Penguin(Bird):
    def fly(self):
        raise NotImplementedError("Cannot fly!")

def let_bird_fly(bird: Bird):
    print(bird.fly())

# Usage
blue_bird = Bird()
let_bird_fly(blue_bird)  # Fonctionne bien

happy_feet = Penguin()
let_bird_fly(happy_feet)  # Lève NotImplementedError

Dans cet exemple, la classe Bird a une méthode fly(). La classe Penguin, une sous-classe de Bird, remplace la méthode fly() mais change radicalement son comportement en levant une NotImplementedError, indiquant que les pingouins ne peuvent pas voler. Cela viole le PSL car les objets Penguin ne peuvent pas être utilisés comme substituts aux objets Bird sans altérer la correction du programme, spécifiquement dans la fonction let_bird_fly. Cette fonction s'attend à ce que tout objet Bird (ou sa sous-classe) puisse voler, mais Penguin brise cette attente en changeant le comportement de la méthode fly().

Refactoriser le Code pour Adhérer au PSL

Pour refactoriser le code Python fourni afin d'adhérer au Principe de Substitution de Liskov (PSL), nous devons restructurer la hiérarchie des classes de manière à ce que les sous-classes de Bird ne l'étendent que si elles peuvent remplir son contrat (c'est-à-dire si elles peuvent implémenter toutes ses méthodes sans changer leur comportement attendu). Voici à quoi ressemblerait le code refactorisé :

class Bird:

    def move(self):
        return "Je peux bouger !"

class FlyingBird(Bird):
    def fly(self):
        return "Je peux voler !"

class Penguin(Bird):
    # Le Pingouin ne remplace pas la méthode fly
    pass

def let_bird_fly(bird: FlyingBird):
    print(bird.fly())

# Utilisation
eagle = FlyingBird()
let_bird_fly(eagle)  # Fonctionne bien

happy_feet = Penguin()
# let_bird_fly(happy_feet)  # Cette ligne va maintenant entraîner une erreur de type, et non une erreur de comportement

Dans cette version refactorisée, Bird est une classe générale sans la méthode fly. Nous créons une nouvelle sous-classe FlyingBird qui inclut les oiseaux capables de voler et implémente donc la méthode fly. Cette structure garantit que seuls les oiseaux volants sont passés à des fonctions ou des scénarios où le vol est attendu, adhérant ainsi au PSL en assurant que les sous-classes peuvent être utilisées de manière interchangeable avec leur classe de base sans altérer la correction du programme.

Le PSL en Action : Exemple Pratique en Python

Pour démontrer le Principe de Substitution de Liskov (PSL) en action, considérez un système de traitement des paiements en Python. Cet exemple montrera comment les sous-classes peuvent être utilisées de manière interchangeable avec leur classe de base sans changer le comportement du programme, adhérant ainsi au PSL.

class Payment:
    def process_payment(self, amount):
        raise NotImplementedError

class CreditCardPayment(Payment):
    def process_payment(self, amount):
        return f"Traitement du paiement par carte de crédit pour {amount}"

class DebitCardPayment(Payment):
    def process_payment(self, amount):
        return f"Traitement du paiement par carte de débit pour {amount}"

class PayPalPayment(Payment):
    def process_payment(self, amount):
        return f"Traitement du paiement PayPal pour {amount}"

def process_transaction(payment_method: Payment, amount):
    print(payment_method.process_payment(amount))

# Utilisation
credit_payment = CreditCardPayment()
process_transaction(credit_payment, 100)

debit_payment = DebitCardPayment()
process_transaction(debit_payment, 100)

paypal_payment = PayPalPayment()
process_transaction(paypal_payment, 100)

Dans cet exemple, chaque sous-classe (CreditCardPayment, DebitCardPayment, PayPalPayment) de la classe Payment implémente la méthode process_payment. La fonction process_transaction peut fonctionner avec n'importe laquelle de ces méthodes de paiement, démontrant que les sous-classes peuvent se substituer à la classe de base (Payment) sans affecter le comportement de la fonction, adhérant ainsi au PSL.

Conclusion du PSL en Python

Le Principe de Substitution de Liskov est plus qu'une directive ; c'est un fondement pour créer un logiciel orienté objet efficace et fiable. En comprenant et en appliquant le PSL dans la programmation Python, les développeurs peuvent construire des systèmes qui sont non seulement efficaces mais aussi évolutifs et faciles à maintenir. C'est un principe qui souligne l'importance d'une conception de classe réfléchie, assurant que les sous-classes représentent véritablement une relation de type "est-une" avec leurs superclasses.

Rappelez-vous, la puissance du PSL réside dans sa simplicité et son impact profond sur l'intégrité et la robustesse de la conception logicielle.

Return to blog

Recevez notre newsletter