Quelle est la différence entre les modèles Bridge et Adapter?
Quelle est la différence entre les modèles Bridge et Adapter?
Réponses:
"L'adaptateur fait fonctionner les choses après leur conception; Bridge les fait fonctionner avant qu'elles ne le soient. [GoF, p219]"
En effet, le modèle d' adaptateur est utile lorsque vous avez du code existant, qu'il soit tiers ou en interne, mais hors de votre contrôle, ou autrement non modifiable pour répondre tout à fait à l'interface dont vous en avez besoin. Par exemple, nous avons un SuperWeaponsArray qui peut contrôler un large éventail d'appareils apocalyptiques.
public class SuperWeaponsArray {
/*...*/
public void destroyWorld() {
for (Weapon w : armedWeapons) {
w.fire();
}
}
}
Génial. Sauf que nous nous rendons compte que nous avons un dispositif nucléaire dans notre arsenal qui est largement antérieur à la conversion à l'interface Weapon. Mais nous aimerions vraiment que cela fonctionne ici ... alors que faisons-nous ... coincez-le!
NukeWeaponsAdaptor - basé sur notre classe Nuke, mais exportant l'interface Weapon. Doux, maintenant nous pouvons sûrement détruire le monde. Cela semble un peu un kludge, mais cela fait fonctionner les choses.
Le modèle Bridge est quelque chose que vous implémentez à l'avance - si vous savez que vous avez deux hiérarchies orthogonales, il fournit un moyen de découpler l'interface et l'implémentation de manière à ne pas obtenir un nombre insensé de classes. Disons que vous avez:
Types d'objets de fichier MemoryMappedFile et DirectReadFile. Supposons que vous souhaitiez pouvoir lire des fichiers à partir de diverses sources (peut-être des implémentations Linux ou Windows, etc.). Bridge vous aide à éviter de vous retrouver avec:
MemoryMappedWindowsFile MemoryMappedLinuxFile DirectReadWindowsFile DirectReadLinuxFile
http://en.wikipedia.org/wiki/Adapter_pattern
Le modèle d'adaptateur consiste davantage à faire fonctionner votre code existant avec un système ou une interface plus récent.
Si vous disposez d'un ensemble d'API de service Web standard de l'entreprise que vous souhaitez proposer à l'interface d'extensibilité existante d'une autre application, vous pouvez envisager d'écrire un ensemble d'adaptateurs pour ce faire. Notez qu'il y a une zone grise et il s'agit davantage de la façon dont vous définissez techniquement le motif, car d'autres motifs comme la façade sont similaires.
http://en.wikipedia.org/wiki/Bridge_pattern
Le modèle Bridge va vous permettre d'avoir éventuellement des implémentations alternatives d'un algorithme ou d'un système.
Bien que ce ne soit pas un exemple de modèle de pont classique, imaginez si vous aviez quelques implémentations d'un magasin de données: l'une est efficace dans l'espace, l'autre est efficace en termes de performances brutes ... et vous avez une analyse de rentabilisation pour offrir les deux dans votre application ou votre framework .
En ce qui concerne votre question, «où je peux utiliser quel modèle», la réponse est, partout où cela a du sens pour votre projet! Envisagez peut-être de proposer une clarification pour guider la discussion sur les domaines dans lesquels vous pensez devoir utiliser l'un ou l'autre.
Adaptateur:
Diagramme UML: à partir dofactory article:
Cible : définit l'interface spécifique au domaine que le client utilise.
Adapter : adapte l'interface Adaptee à l'interface Target.
Adaptee : définit une interface existante qui doit être adaptée.
Client : collabore avec des objets conformes à l'interface Target.
Exemple:
Square et Rectangle sont deux formes différentes et obtenir la zone () de chacune d'elles nécessite des méthodes différentes. Mais Square travaille toujours sur l'interface Rectangle avec la conversion de certaines propriétés.
public class AdapterDemo{
public static void main(String args[]){
SquareArea s = new SquareArea(4);
System.out.println("Square area :"+s.getArea());
}
}
class RectangleArea {
public int getArea(int length, int width){
return length * width;
}
}
class SquareArea extends RectangleArea {
int length;
public SquareArea(int length){
this.length = length;
}
public int getArea(){
return getArea(length,length);
}
}
Pont:
EDIT: (selon la suggestion @quasoft)
Vous avez quatre composants dans ce modèle.
Abstraction : elle définit une interface
RefinedAbstraction : Il implémente l'abstraction:
Implémenteur : il définit une interface pour l'implémentation
ConcreteImplementor : il implémente l'interface Implémenteur.
Extrait de code:
Gear gear = new ManualGear();
Vehicle vehicle = new Car(gear);
vehicle.addGear();
gear = new AutoGear();
vehicle = new Car(gear);
vehicle.addGear();
Article similaire:
Quand utilisez-vous le modèle de pont? En quoi est-ce différent du modèle d'adaptateur?
Principales différences: d' après l' article sur la création de sources
Ce message existe depuis un certain temps. Cependant, il est important de comprendre qu'une façade est un peu similaire à un adaptateur mais ce n'est pas tout à fait la même chose. Un adaptateur «adapte» une classe existante à une classe client généralement non compatible. Disons que vous disposez d'un ancien système de flux de travail que votre application utilise en tant que client. Votre entreprise pourrait éventuellement remplacer le système de workflow par un nouveau "incompatible" (en termes d'interfaces). Dans la plupart des cas, vous pouvez utiliser le modèle d'adaptateur et écrire du code qui appelle réellement les interfaces du nouveau moteur de workflow. Un pont est généralement utilisé d'une manière différente. Si vous avez réellement un système qui doit fonctionner avec différents systèmes de fichiers (c'est-à-dire disque local, NFS, etc.), vous pouvez utiliser le modèle de pont et créer une couche d'abstraction pour fonctionner avec tous vos systèmes de fichiers. Ce serait essentiellement un cas d'utilisation simple pour le modèle de pont. La façade et l'adaptateur partagent certaines propriétés maisles façades sont généralement utilisées pour simplifier une interface / classe existante . Au début des EJB, il n'y avait pas d'appels locaux pour les EJB. Les développeurs obtenaient toujours le stub, le réduisaient et l'appelaient «pseudo-à distance». Cela causait souvent des problèmes de performances (surtout lorsqu'ils étaient vraiment appelés sur le fil). Les développeurs expérimentés utiliseraient le modèle de façade pour fournir une interface très grossière au client. Cette façade ferait alors à son tour plusieurs appels à différentes méthodes plus fines. Dans l'ensemble, cela a considérablement réduit le nombre d'appels de méthode requis et augmenté les performances.
Bridge est un adaptateur amélioré. Bridge inclut un adaptateur et lui ajoute une flexibilité supplémentaire. Voici comment les éléments de la réponse de Ravindra mappent entre les motifs:
Adapter | Bridge
-----------|---------------
Target | Abstraction
-----------|---------------
| RefinedAbstraction
|
| This element is Bridge specific. If there is a group of
| implementations that share the same logic, the logic can be placed here.
| For example, all cars split into two large groups: manual and auto.
| So, there will be two RefinedAbstraction classes.
-----------|---------------
Adapter | Implementor
-----------|---------------
Adaptee | ConcreteImplementor
Dans la première réponse, @James cite une phrase du GoF, page 219. Je pense qu'il vaut la peine de reproduire l'explication complète ici.
Adaptateur contre pont
Les modèles d'adaptateur et de pont ont des attributs communs. Les deux favorisent la flexibilité en fournissant un niveau d'indirection vers un autre objet. Les deux impliquent de transmettre des requêtes à cet objet à partir d'une interface autre que la sienne.
La principale différence entre ces modèles réside dans leurs intentions. L'adaptateur se concentre sur la résolution des incompatibilités entre deux interfaces existantes. Il ne se concentre pas sur la manière dont ces interfaces sont implémentées, ni ne considère comment elles pourraient évoluer de manière indépendante. C'est une façon de faire fonctionner ensemble deux classes conçues indépendamment sans réimplémenter l'une ou l'autre. Bridge, d'autre part, relie une abstraction et ses implémentations (potentiellement nombreuses). Il fournit une interface stable aux clients tout en vous permettant de varier les classes qui l'implémentent. Il accueille également de nouvelles implémentations au fur et à mesure que le système évolue.
En raison de ces différences, l'adaptateur et le pont sont souvent utilisés à différents moments du cycle de vie du logiciel. Un adaptateur devient souvent nécessaire lorsque vous découvrez que deux classes incompatibles doivent fonctionner ensemble, généralement pour éviter la réplication du code. Le couplage est imprévu. En revanche, l'utilisateur d'un pont comprend d'avance qu'une abstraction doit avoir plusieurs implémentations, et les deux peuvent évoluer indépendamment. Le modèle Adapter fait fonctionner les choses après leur conception; Bridge les fait travailler avant qu'ils ne le soient. Cela ne veut pas dire que l'adaptateur est en quelque sorte inférieur à Bridge; chaque modèle aborde simplement un problème différent.
Supposons que vous ayez une classe Shape abstraite avec une fonctionnalité de dessin (générique / abstraite) et un Circle qui implémente la forme. Le modèle de pont est simplement une approche d'abstraction bidirectionnelle pour découpler l'implémentation (dessin dans Circle) et la fonctionnalité générique / abstraite (dessin dans la classe Shape).
Qu'est-ce que cela signifie vraiment? À première vue, cela ressemble à quelque chose que vous faites déjà (par inversion de dépendance). Donc, ne vous inquiétez pas d'avoir une base de code moins ridig ou plus modulaire. Mais c'est une philosophie un peu plus profonde derrière cela.
D'après ma compréhension, le besoin d'un modèle d'utilisation peut émerger lorsque j'ai besoin d'ajouter de nouvelles classes qui sont étroitement liées au système actuel (comme RedCircle ou GreenCircle) et dont elles ne diffèrent que par une seule fonctionnalité (comme la couleur). Et je vais avoir besoin du modèle Bridge en particulier si les classes système existantes (Circle ou Shape) doivent être fréquemment modifiées et que vous ne voulez pas que les classes nouvellement ajoutées soient affectées par ces changements. C'est pourquoi la fonctionnalité de dessin générique est abstraite dans une nouvelle interface afin que vous puissiez modifier le comportement de dessin indépendamment de la forme ou du cercle.