Chaine de responsabilité, utiliser ce patron de conception avec Python

Dans ce tutoriel, nous apprendrons pourquoi et comment utiliser le design pattern Chaine de responsabilité.

Nous le définirons puis l’analyserons au travers d’un exemple pratique avec Python.

Pré-requis : Avoir les bases en programmation orientée objet => Tutoriel OpenClassroom

upidev patron de conception chaine de responsabilité python

Définition Chaine de responsabilité : :

Patron de conception qui permet à un nombre quelconque de classes d’essayer de répondre à une requête sans connaître les possibilités des autres classes sur cette requête. Cela permet de diminuer le couplage entre objets. Le seul lien entre ces objets est la requête qui passe jusqu’à que l’un des objets puissent y répondre.

Exemple pratique :

On souhaite retirer des billets depuis un distributeur à partir d’une somme initiale.
Ex : $25 = 20 * 1 + 5 * 1
Afin de retirer les billets en conséquence, on souhaite que les billets retirés soit déduits de la somme initiale.

Classe abstraite ( Handler )

Commençons par créer, une classe Handler regroupant les méthodes utilisées pour gérer le retrait des billets.

class Handler:

    def __init__(self, successor=None):
        self._successor = successor

    def handle(self, request):
        if request:
            res = self._handle(request)
            if res != 0:
                self._successor.handle(res)
            else:
                print(" ==> Notes available !!")
        else:
            print("Choose an another amount than 0 to withdraw money")

    def _handle(self, request):
        raise NotImplementedError('Must Provide implementation in subclass')

    def dispense_bills(self, request, note_value):
        if request:
            dividend = request // note_value
            amount_to_substract = note_value * dividend

            print("Dispense {0} notes of ${1} = {2}".format(dividend, note_value, amount_to_substract))
            request -= amount_to_substract
        return request

Gérer le retrait des billets

A présent, nous souhaitons retirer les billets à partir de la somme initiale définie.
Pour chaque billet à retirer, nous pouvons créer une sous classe qui retirera le maximum de billet ( 1 ) pour sa valeur ( $20 ) de la somme initialement définie. ( $25 )

# Dispense $50 notes
class note_50_Handler(Handler):
    def _handle(self, request):
        return self.dispense_bills(request, 50)

# Dispense $20 notes
class note_20_Handler(Handler):
    def _handle(self, request):
        return self.dispense_bills(request, 20)

# Dispense $10 notes
class note_10_Handler(Handler):
    def _handle(self, request):
        return self.dispense_bills(request, 10)

# Dispense $5 notes
class note_05_Handler(Handler):
    def _handle(self, request):
        return self.dispense_bills(request, 5)

class DefaultHandler(Handler):
    def _handle(self, request):
        print('No handler for {}, unable to dispense the amount'.format(request))
        return False

Retrait de billet pour de vrai

Ci dessous, on définit notre distributeur automatique qui en fonction des demandes retournera des billets dans l’ordre suivant ( $50 -> $20 -> $10 -> $5 -> ? Non traité).

class ATM:
    def __init__(self):
        self.handler = note_50_Handler(note_20_Handler(note_10_Handler(note_05_Handler(DefaultHandler()))))

    def process(self, requests):
        for request in requests:
            self.handler.handle(request)
            print("*" * 60)


if __name__ == "__main__":
    atm = ATM()

    requests = [250, 260, 285, 287.5, 0]

    atm.process(requests)

Conclusion

Félicitations, vous venez de terminer ce tutoriel. Vous savez à présent comment utiliser le patron de conception Chaine de responsabilité

0

Laisser un commentaire