Le modèle de conception de pont sépare l'implémentation de l'interface d'un programme.
Pourquoi est-ce avantageux?
design-patterns
David Faux
la source
la source
Réponses:
Il vous permet de modifier l'implémentation indépendamment de l'interface. Cela permet de faire face à l'évolution des exigences.
L'exemple classique consiste à remplacer l'implémentation de stockage sous une interface par quelque chose de plus grand, de meilleur, de plus rapide, de plus petit ou autrement différent sans avoir à changer le reste du système.
la source
En plus de la réponse de Daniel, séparer l'interface de l'implémentation à travers des concepts comme le polymorphisme vous permet de créer plusieurs implémentations de la même interface qui font des choses similaires de différentes manières.
Par exemple, de nombreuses langues ont un concept de flux quelque part dans la bibliothèque standard. Un flux est quelque chose qui contient des données pour un accès série. Il a deux opérations de base: lire (charger le prochain nombre X d'octets du flux) et écrire (ajouter X nombre d'octets de données au flux), et parfois une troisième, chercher (réinitialiser la "position actuelle" du flux vers un nouvel emplacement).
C'est un concept assez simple, mais pensez à tout ce que vous pourriez en faire. Le plus évident est d'interagir avec les fichiers du disque. Un flux de fichiers vous permettrait de lire des données à partir d'un fichier ou d'y écrire. Mais que se passe-t-il si vous souhaitez plutôt envoyer des données via une connexion réseau?
Si vous dépendiez directement des implémentations, vous devrez écrire deux routines complètement différentes pour enregistrer les mêmes données dans un fichier ou pour les envoyer sur le réseau. Mais si vous avez une interface de flux, vous pouvez en créer deux implémentations différentes (
FileStream
etNetworkStream
) qui encapsulent les détails spécifiques de l'envoi des données là où elles doivent aller, puis il vous suffit d'écrire le code qui traite de l'enregistrement d'un fichier une fois . Soudain, vos routinesSaveToFile
etSendOverNetwork
sont beaucoup plus simples: elles configurent simplement un flux du type approprié et le transmettent à laSaveData
routine, qui accepte une interface de flux - il n'a pas besoin de se soucier de quel type, tant qu'il peut effectuer la Opération d'écriture - et enregistre les données dans le flux.Cela signifie également que si votre format de données change, vous n'avez pas à le modifier à plusieurs endroits différents. Si vous centralisez votre code d'enregistrement de données dans une routine qui prend un flux, alors c'est le seul endroit où il doit être mis à jour, donc vous ne pouvez pas accidentellement introduire un bogue en changeant un seul endroit lorsque vous avez besoin de changer les deux. Ainsi, séparer les interfaces des implémentations et utiliser le polymorphisme rend le code plus simple à lire et à comprendre, et moins susceptible d'avoir des bogues.
la source
IStream
interface, vous devez réinventer l'ensemble des fonctionnalités de chaque flux. Mais si vous commencez avec une classe de flux abstraite de base, elle peut contenir tous les états et fonctionnalités communs, puis laisser les descendants implémenter les fonctionnalités distinctes.Vous avez vraiment deux questions très différentes ici, bien qu'elles soient liées.
La question plus générale est celle du titre, pourquoi sépareriez-vous l'interface de l'implémentation en général. La deuxième question est de savoir pourquoi le motif de pont est utile. Ils sont liés parce que le modèle de pont est un moyen spécifique de séparer l'interface de l'implémentation, ce qui a également d'autres conséquences spécifiques.
La question générale est quelque chose de vital pour tout programmeur à comprendre. C'est ce qui empêche les changements dans un programme de se propager partout. Je ne peux pas imaginer que les humains puissent programmer sans utiliser cela.
Lorsque vous écrivez une simple instruction d'addition dans un langage de programmation, c'est déjà une abstraction (même si elle n'utilise pas de surcharge d'opérateur pour ajouter des matrices ou quelque chose comme ça) qui passe par beaucoup d'autres codes avant d'être finalement exécutée. sur un circuit de votre ordinateur. S'il n'y avait pas de séparation de l'interface (par exemple, "3 + 5"), de l'implémentation (un tas de code machine), alors vous devriez changer votre code chaque fois que l'implémentation change (comme si vous vouliez exécuter sur un nouveau processeur).
Même au sein d'une simple application CRUD, chaque signature de méthode est, au sens large, l'interface de son implémentation.
Tous ces types d'abstraction ont le même objectif de base - demander au code appelant d'exprimer son intention de la manière la plus abstraite possible qui donne à l'implémenteur autant d'informations que nécessaire. Cela fournit le couplage minimal possible entre eux et limite l'effet d'entraînement lorsque le code doit être modifié autant que possible.
Cela semble simple, mais dans la pratique, cela se complique.
Le modèle de pont est une manière spécifique de séparer certains bits d'implémentation en interfaces. Le diagramme de classes du modèle est plus informatif que la description. Cela ressemble plus à un moyen d'avoir des modules enfichables qu'à un pont, mais ils l'ont appelé pont car il est souvent utilisé là où les modules ont été créés avant l'interface. Ainsi, la création d'une interface commune pour des implémentations existantes similaires sorte de «combler» la différence et vous permet de travailler avec n'importe laquelle des implémentations.
Supposons donc que vous vouliez écrire un module complémentaire sur un traitement de texte, mais que vous souhaitiez qu'il fonctionne sur plusieurs traitements de texte. Vous pouvez créer une interface qui résume les fonctionnalités basées sur le traitement de texte dont vous avez besoin (et qui doivent être implémentables par chaque traitement de texte car vous ne pouvez pas les modifier), et un implémenteur de cette interface pour chaque traitement de texte que vous souhaitez prendre en charge. Ensuite, votre application peut appeler cette interface et ne pas se soucier des détails de chaque traitement de texte.
C'est en fait un peu plus détaillé que cela, parce que chaque classe peut vraiment être une hiérarchie de classe (donc, il peut ne pas y avoir seulement un traitement de texte abstrait, mais un Document abstrait, TextSelection abstrait, etc., avec des implémentations concrètes pour chacune), mais c'est la même idée.
C'est un peu comme une façade, sauf que dans ce cas, la couche d'abstraction se concentre sur la fourniture de la même interface à plusieurs systèmes sous-jacents.
Il est lié à Inversion Of Control, car l'implémenteur concret sera passé aux méthodes ou aux constructeurs et déterminera l'implémentation réelle appelée.
la source