Sur le Pont d'avignon

03 mai 2023


PATRON DE STRUCTURE : PONT


illustration

L'objectif pour ce patron de conception est de découpler la logique abstraite et les implémentations concrètes de notre code. C'est à dire séparer la logique de l'implémentation de la logique de l'abstraction. Ce patron de conception permet donc de créer un "pont" entre les concrétisations des différentes implémentations en cachant leurs différences. Il ne doit pas être confondu avec le patron de conception Adapteur qui permet de faire communiquer deux interfaces incompatibles entre elles. (au prochain épisode !).


Mettons par exemple qu'une entreprise cherche à envoyer un message à un client. l'idée est ainsi de communiquer une information. Il n'en reste pas moins qu'il existe de nombreuses manières d'"envoyer un message" concrètement. Le Pont permet ainsi de structurer le code de manière à cacher l'implémentation concrète de l'abstraction tout en tenant compte de ces spécificités.

Codons un exemple :


class SMS:
	"""Implémentation spécifique de notre abstraction"""
	def envoyerMessage(self, length, content, importance):
		print(f'le SMS envoie des messages de longueur {length},' +
		f' de contenue {content} et important : {importance}')

class Email:
"""Implémentation spécifique de notre abstraction"""
def envoyerMessage(self, length, content, importance):
print(f'même principe pour avec autres types')

Nous avons bien deux moyens de contacter nos clients en pratique. Mais l'idée est la même. Leur faire passer un message :



class Message:

    def __init__(self, length, content, importance, implementation):
    	"""On initialise avec les paramètres de notre message"""
    	self._length = length
    	self._content = content
    	self._importance = importance

# On stocke l'implémentation spécifique à un message particulier ici (SMS ou Email)

    	self._implementation = implementation

    def envoyer(self):
    	"""On envoie en utilisant l'implémentation spécifique (méthode de SMS vs de Email)"""
    	self._implementation.envoyerMessage(self._length,
    										self._content,
    										self._importance)

    def recordClientMessage(self):
    	"""Implémentation indépendante de abstraction (dans tous les cas)"""
    	print('On enregistre une confirmation',
    		' pour envoie dans notre base de données');
    

Ainsi, on peut désormais "instancier" nos implémentations spécifiques :



sms = SMS()
email = Email()
		

puis créer nos messages avec celles-ci :



message1 = Message(10, 'Salut', 'faible', sms)
message2 = Message(100, 'Salut', 'faible', email)
		

pour les envoyer, pas besoin de s'inquiéter de leurs spécificités respectives :



message1.envoyer()
message2.envoyer()

# On enregistre nos messages dans notre base de données

# (on le fait dans tous les cas indépendamment de l'implémentation utilisée)

message1.recordClientMessage()
message2.recordClientMessage()

TADA !

On peut changer l'implémentation utilisée à la volée ou en ajouter de nouvelles Le "pont" est, dans notre cas, l'implémentation de notre classe Message. S'il y a des erreurs ici, n'hésitez pas à me le faire savoir.


A la prochaine

Vous pouvez retrouver un autre exemple, certainement mieux expliquer et avec des illustrations sur :

Geeks for Geeks