Introduction
La Modèle de conception d'adaptateur est un populaire Modèle de conception structurelle utilisé en génie logiciel. Ce guide explique comment nous pouvons implémenter le modèle de conception d'adaptateur en Python.
Modèles de conception sont des solutions de type modèle - pratiquement des recettes pour résoudre des problèmes récurrents et courants dans le développement de logiciels. Le modèle d'adaptateur est basé sur le concept d'un adaptateur du monde réel ! Par exemple, le chargeur d'un ordinateur portable peut avoir une prise à 3 broches à l'extrémité, mais la prise murale peut n'être qu'une prise à 2 broches. Pour brancher un chargeur à 3 broches dans cette prise, nous aurions besoin d'un adaptateur, qui accepte une prise à 3 broches, et s'adapte l'interface dans le 2 broches prise.
Un chargeur à 2 broches et un chargeur à 3 broches ont la même fonction de base (conduisent l'électricité de la prise à l'ordinateur portable), mais ont une forme différente, et on peut facilement adapter dans l'autre. Chaque fois que vous avez des composants logiciels avec la même fonction de base mais des formes différentes, vous pouvez appliquer le modèle de conception d'adaptateur.
Le modèle d'adaptateur suit ce principe exact. Il permet à deux interfaces incompatibles de fonctionner ensemble sans modifier les composants internes de chaque composant. Ceci est réalisé en adaptant une interface, à une autre, en externe.
Examinons quelques termes de base avant de plonger plus profondément dans le monde des Adapter Patterns :
- Interface client: Une interface qui spécifie les fonctions que le client doit implémenter.
- Client: Une classe qui implémente l'interface client.
- Adapté/Service: La classe incompatible qui doit collaborer avec l'interface client.
- adaptateur: La classe qui rend possible la collaboration entre le service et le client.
Différents types de modèles d'adaptateur
Le modèle de conception d'adaptateur peut être implémenté de deux manières différentes :
Adaptateur d'objet
Avec cette méthode, la classe adaptateur implémente les méthodes de l'interface client. Ainsi, l'objet client et l'objet adaptateur sont compatibles entre eux. L'objet de service forme un has-a
relation avec l'objet adaptateur, c'est-à-dire que l'objet service appartient à l'objet adaptateur.
Nous savons que la classe de service n'est pas compatible avec le client. La classe d'adaptateur s'enroule autour de l'objet de service en s'instanciant avec cet objet. Désormais, l'objet service est accessible via l'objet adaptateur, ce qui permet au client d'interagir avec lui.
Nous pouvons implémenter l'adaptateur d'objet dans tous les langages de programmation modernes.
Adaptateur de classe
Avec cette méthode, l'adaptateur a un is-a
relation avec la classe de service. Dans ce scénario, l'adaptateur implémente les méthodes requises par le client, mais il hérite de plusieurs adaptateurs, ce qui lui donne la possibilité d'appeler directement leurs fonctions incompatibles. Le plus gros inconvénient de cette variante est que nous ne pouvons l'utiliser que dans les langages de programmation qui prennent en charge l'héritage multiple de classes.
Implémentation du modèle de conception d'adaptateur en Python
Dans la section ci-dessous, nous allons implémenter le modèle de conception Adapter en Python, en utilisant spécifiquement le variation de l'adaptateur d'objet. La section est divisée en deux parties. Tout d'abord, nous allons créer l'environnement dans lequel le modèle d'adaptateur doit être utilisé. Il est important de voir clairement comment ce modèle peut résoudre certains problèmes logiciels. La deuxième section utilisera un adaptateur pour résoudre le problème.
Problème d'incompatibilité entre les classes
Examinons le problème de compatibilité lorsque le client et la classe de service implémentent des fonctionnalités différentes. Créez une classe client avec les méthodes suivantes et enregistrez-la dans un dossier sous car.py
:
import random
class Car:
def __init__(self):
self.generator = random.Random()
def accelerate(self):
random_num = self.generator.randint(50, 100)
speed = random_num
print(f"The speed of the car is {speed} mph")
def apply_brakes(self):
random_num = self.generator.randint(20, 40)
speed = random_num
print(f"The speed of the car is {speed} mph after applying the brakes")
def assign_driver(self, driver_name):
print(f"{driver_name} is driving the car")
Ici, nous avons créé un Car
classe avec trois méthodes accelerate()
, apply_brakes()
ainsi que assign_driver()
. Nous avons importé le random
module et l'a utilisé pour générer des nombres qui définissent la vitesse de la voiture après avoir accéléré et appliqué les freins. Le assign_driver()
méthode affiche le nom du conducteur de la voiture.
Ensuite, il faut créer une classe service ou adaptée qui souhaite collaborer avec la classe client Car
. Créez une classe de moto comme celle-ci et enregistrez-la dans votre dossier sous motorcycle.py
:
import random
class Motorcycle:
def __init__(self):
self.generator = random.Random()
def rev_throttle(self):
random_num = self.generator.randint(50, 100)
speed = random_num
print(f"The speed of the motorcycle is {speed} mph")
def pull_brake_lever(self):
random_num = self.generator.randint(20, 40)
speed = random_num
print(
f"The speed of the motorcycle is {speed} mph after applying the brakes")
def assign_rider(self, rider_name):
print(f"{rider_name} is riding the motorcycle")
Une classe de service, Motorcycle
est créé ci-dessus avec trois méthodes rev_throttle()
, pull_brake_lever()
et assign_rider()
. Notez la différence entre les méthodes de la classe service et client malgré leurs fonctionnalités similaires. Le accelerator()
méthode augmente la vitesse de la voiture tandis que la rev_throttle()
méthode augmente la vitesse de la moto. De même, apply_brakes()
ainsi que pull_brake_lever()
applique les freins dans les véhicules respectifs. Finalement, le assign_driver()
ainsi que assign_rider()
méthodes assignent le conducteur du véhicule.
Créons ensuite une classe pour accéder à ces différentes méthodes. Tout d'abord, ajoutez un __init.py__
dans le même dossier que vous avez créé car.py
ainsi que motorcycle.py
:
touch __init__.py
Ajoutez maintenant le code suivant dans un nouveau fichier drive.py
:
from car import Car
from motorcycle import Motorcycle
import traceback
if __name__ == '__main__':
car = Car()
bike = Motorcycle()
print("The Motorcyclen")
bike.assign_rider("Subodh")
bike.rev_throttle()
bike.pull_brake_lever()
print("n")
print("The Carn")
car.assign_driver("Sushant")
car.accelerate()
car.apply_brakes()
print("n")
print("Attempting to call client methods with the service objectn")
try:
bike.assign_driver("Robert")
bike.accelerate()
bike.apply_brakes()
except AttributeError:
print("Oops! bike object cannot access car methods")
traceback.print_exc()
Ce script qui crée nos objets client et service. Nous importons d'abord le Car
ainsi que Motorcycle
classes et créer des objets avec eux. Ensuite, nous invoquons les méthodes de la bike
objet (Motorcycle
classe). Ensuite, nous invoquons les méthodes de la car
objet (Car
classe). Une fois exécuté, tout le code mentionné jusqu'à présent fonctionnera.
Cependant, une exception est levée lorsque nous essayons d'invoquer les méthodes du Car
classe avec le bike
objet. Lorsque nous exécutons ce script :
The Motorcycle
Subodh is riding the motorcycle
The speed of the motorcycle is 91 mph
The speed of the motorcycle is 37 mph after applying the brakes
The Car
Sushant is driving the car
The speed of the car is 59 mph
The speed of the car is 33 mph after applying the brakes
Attempting to call client methods with the service object
Oops! bike object cannot access car methods
Traceback (most recent call last):
File "drive.py", line 24, in
bike.assign_driver("Robert")
AttributeError: 'Motorcycle' object has no attribute 'assign_driver'
Dans ce cas, nous pouvons modifier le Motorcycle
classe ou le drive.py
script pour utiliser les bonnes méthodes. Cependant, dans de nombreux cas, nous n'avons peut-être pas accès au code source du client ou de la classe de service. En outre, ceci est un exemple simple. Avec des clients et des services plus importants, il peut ne pas être possible de refactoriser l'un ou l'autre au cas où nous briserions la compatibilité avec d'autres systèmes.
Au lieu de cela, nous pouvons utiliser un adaptateur pour combler le fossé de compatibilité entre notre code client et notre objet de service.
Utilisation d'adaptateurs pour résoudre le problème d'incompatibilité
Dans un nouveau fichier, motorcycle_adapter.py
, ajoutez la classe suivante :
class MotorcycleAdapter:
def __init__(self, motorcycle):
self.motorcycle = motorcycle
def accelerate(self):
self.motorcycle.rev_throttle()
def apply_brakes(self):
self.motorcycle.pull_brake_lever()
def assign_driver(self, name):
self.motorcycle.assign_rider(name)
Nous avons créé un MotorcycleAdapter
classe, qui s'instancie avec un objet de service (motorcycle
). L'adaptateur implémente les méthodes client qui sont accelerate()
, apply_brakes()
ainsi que assign_driver()
. A l'intérieur du corps du accelerate()
méthode, nous avons utilisé la motorcycle
instance de l'objet de service pour appeler le rev_throttle()
méthode des services. De même, les autres méthodes utilisent les méthodes correspondantes de la Motorcycle
classe.
Maintenant, mettons à jour drive.py
afin que nous puissions utiliser l'adaptateur dans le try/except
bloquer:
from car import Car
from motorcycle import Motorcycle
from motorcycle_adapter import MotorcycleAdapter
import traceback
if __name__ == '__main__':
car = Car()
bike = Motorcycle()
bike_adapter = MotorcycleAdapter(bike)
...
try:
print("Attempting to call client methods with the service object using an adaptern")
bike_adapter.assign_driver("Robert")
bike_adapter.accelerate()
bike_adapter.apply_brakes()
except AttributeError:
print("Oops! bike object cannot access car methods")
traceback.print_exc()
Ici,bike_adapter
est un objet de la MotorcycleAdapter
classe. Nous avons fourni le bike
objet à la MotorcycleAdapter
constructeur de la classe. L'exécution de ce script nous donne le résultat suivant :
Consultez notre guide pratique et pratique pour apprendre Git, avec les meilleures pratiques, les normes acceptées par l'industrie et la feuille de triche incluse. Arrêtez de googler les commandes Git et en fait apprendre il!
The Motorcycle
Subodh is riding the motorcycle
The speed of the motorcycle is 88 mph
The speed of the motorcycle is 35 mph after applying the brakes
The Car
Sushant is driving the car
The speed of the car is 91 mph
The speed of the car is 24 mph after applying the brakes
Attempting to call client methods with the service object
Attempting to call client methods with the service object using an adapter
Robert is riding the motorcyle
The speed of the motorcycle is 67 mph
The speed of the motorcycle is 25 mph after applying the brakes
Sans avoir à ajuster le sous-jacent Motorcycle
classe, nous pouvons le faire fonctionner comme un Car
à l'aide d'un adaptateur !
Avantages et inconvénients du modèle de conception d'adaptateur
Les avantages des modèles d'adaptateur sont :
- Nous pouvons obtenir un faible couplage entre la classe adaptateur et la classe client.
- Nous pouvons réutiliser la classe d'adaptateur pour incorporer de nombreuses classes de service dans l'application.
- Nous pouvons augmenter la flexibilité du programme en introduisant plusieurs adaptateurs sans interférer avec le code client
Les inconvénients d'Adapter Pattern sont :
- La complexité du programme augmente avec l'ajout de la classe d'adaptateur et de la classe de service.
- Il y a une augmentation des frais généraux dans le programme à mesure que les demandes sont transmises d'une classe à une autre.
- Adapter Pattern (adaptateur de classe) utilise plusieurs héritages, que tous les langages de programmation peuvent ne pas prendre en charge.
Conclusion
Dans cet article, nous avons découvert le modèle de conception de l'adaptateur, ses types et les problèmes qu'ils résolvent. Nous avons implémenté le modèle d'adaptateur en Python afin que nous puissions interagir avec un Motorcycle
objet, comme un Car
objet en utilisant un adaptateur afin que l'interface de chaque classe ne change pas.