Adapter tervezési minta Pythonban

Bevezetés

A Adapter tervezési minta népszerű szerkezeti tervezési minta szoftverfejlesztésben használják. Ez az útmutató azt mutatja be, hogyan valósíthatjuk meg az Adapter tervezési mintát a Pythonban.

Tervezési minták sablonszerű megoldások – gyakorlatilag receptek a szoftverfejlesztés visszatérő, gyakori problémáinak megoldására. Az Adapter Pattern a valós adapter koncepcióján alapul! Például egy laptop töltőjének lehet 3 tűs csatlakozója a végén, de a fali aljzat csak 2 tűs aljzat lehet. Ahhoz, hogy 3 tűs töltőt csatlakoztassunk ehhez az aljzathoz, szükségünk van egy adapterre, amely 3 tűs csatlakozót is fogad, és alkalmazkodik a felületet a 2-pin foglalat.

Egy 2 tűs töltő és egy 3 tűs töltő van ugyanaz az alapfunkció (áramot vezet a konnektorból a laptopba), de van más forma, és könnyen lehet alkalmazkodni a másikba. Amikor ugyanazzal az alapfunkcióval, de különböző formájú szoftverösszetevőkkel rendelkezik, alkalmazhatja az Adapter tervezési mintát.

Az adapterminta pontosan ezt az elvet követi. Lehetővé teszi, hogy két inkompatibilis interfész együtt működjön anélkül, hogy módosítaná az egyes összetevők belső elemeit. Ezt úgy érik el, hogy az egyik interfészt egy másikhoz külsőleg hozzáigazítják.

Nézzünk meg néhány alapvető terminológiát, mielőtt mélyebbre merülnénk az adapterminták világában:

  • Kliens felület: Olyan interfész, amely meghatározza azokat a funkciókat, amelyeket az ügyfélnek végre kell hajtania.
  • Vásárló: A kliens felületet megvalósító osztály.
  • Alkalmazkodó/Szolgáltatás: Az inkompatibilis osztály, amelynek együtt kell működnie az ügyfélfelülettel.
  • adapter: Az az osztály, amely lehetővé teszi a szolgáltatás és az ügyfél közötti együttműködést.

Különböző típusú adapterminták

Az adapter tervezési mintája két különböző módon valósítható meg:

Tárgyadapter

Ezzel a módszerrel az adapter osztály a kliens felületről valósítja meg a metódusokat. Így a kliens objektum és az adapterobjektum kompatibilis egymással. A szolgáltatás objektum a has-a kapcsolat az adapterobjektummal, azaz a szolgáltatásobjektum az adapterobjektumhoz tartozik.

Tudjuk, hogy a szolgáltatási osztály nem kompatibilis az ügyféllel. Az illesztőosztály körbeveszi a szolgáltatásobjektumot úgy, hogy ezzel az objektummal példányosítja magát. Mostantól a szolgáltatásobjektum elérhető az adapterobjektumon keresztül, lehetővé téve az ügyfél számára, hogy kapcsolatba lépjen vele.

Az objektum adaptert az összes modern programozási nyelven meg tudjuk valósítani.

Osztály adapter

Ezzel a módszerrel az adapter rendelkezik egy is-a kapcsolat a szolgáltatási osztálysal. Ebben a forgatókönyvben az illesztő megvalósítja a kliens által igényelt metódusokat, de több adaptálttól örökli, így képes közvetlenül meghívni az inkompatibilis függvényeiket. Ennek a változatnak a legnagyobb hátránya, hogy csak azokban a programozási nyelvekben tudjuk használni, amelyek támogatják az osztályok többszörös öröklését.

Az Adapter tervezési minta megvalósítása Pythonban

Az alábbi részben megvalósítjuk az Adapter tervezési mintáját Pythonban, kifejezetten a objektum adapter variáció. A szakasz két részre oszlik. Először létrehozzuk azt a környezetet, ahol az Adapter Patternet használni kell. Fontos tisztán látni, hogy ez a minta hogyan oldhat meg néhány szoftverproblémát. A második szakasz adaptert használ a probléma megoldásához.

Összeférhetetlenségi probléma az osztályok között

Nézzük meg a kompatibilitási problémát, amikor az ügyfél és a szolgáltatási osztály különböző funkciókat valósít meg. Hozzon létre egy ügyfélosztályt a következő módszerekkel, és mentse el egy mappába a következő néven 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")

Itt létrehoztuk a Car osztály három módszerrel accelerate(), apply_brakes() és a assign_driver(). importáltuk a random modult, és segítségével olyan számokat generált, amelyek beállítják az autó sebességét a gyorsítás és a fékezés után. A assign_driver() metódus megjeleníti az autóvezető nevét.

Ezután létre kell hoznunk egy szolgáltatást vagy adaptált osztályt, amely együttműködni kíván az ügyfélosztállyal Car. Hozzon létre egy ilyen motorkerékpár-osztályt, és mentse el a mappájába más néven 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")  

Szolgáltatási osztály, Motorcycle fent három módszerrel jön létre rev_throttle(), pull_brake_lever()és assign_rider(). Figyelje meg a különbséget a szolgáltatás és a kliens osztály metódusai között, annak ellenére, hogy hasonló a funkcionalitásuk. A accelerator() módszer növeli az autó sebességét, miközben a rev_throttle() módszer növeli a motorkerékpár sebességét. Hasonlóképpen, apply_brakes() és a pull_brake_lever() fékez az adott járművekben. Végül a assign_driver() és a assign_rider() módszerek rendelik hozzá a jármű üzemeltetőjét.

Ezután hozzunk létre egy osztályt a különböző módszerek eléréséhez. Először adjunk hozzá egy __init.py__ ugyanabban a mappában, amelyet létrehozott car.py és a motorcycle.py:

touch __init__.py

Most adja hozzá a következő kódot egy új fájlhoz 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()

Ez a szkript létrehozza az ügyfél- és szolgáltatásobjektumokat. Először importáljuk a Car és a Motorcycle osztályokat, és objektumokat hozhat létre velük. Ezután meghívjuk a metódusokat a bike tárgy (Motorcycle osztály). Ezt követően a metódusokat hívjuk meg a car tárgy (Car osztály). A végrehajtás után az összes eddig említett kód működni fog.

Kivételt azonban felvetnek, amikor megpróbáljuk meghívni a metódusait Car osztály a bike tárgy. Amikor ezt a szkriptet futtatjuk:

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'

Ebben az esetben módosíthatjuk a Motorcycle osztály vagy a drive.py szkriptet a megfelelő módszerek használatához. Sok esetben azonban előfordulhat, hogy nem férünk hozzá az ügyfél vagy a szolgáltatási osztály forráskódjához. Ráadásul ez egy egyszerű példa. Nagyobb ügyfeleknél és szolgáltatásoknál előfordulhat, hogy egyiket sem lehet újratermelni, ha megszakítjuk a kompatibilitást más rendszerekkel.

Ehelyett egy adapter segítségével áthidalhatjuk az ügyfélkódunk és a szolgáltatásobjektumunk közötti kompatibilitási szakadékot.

Adapterek használata az inkompatibilitási probléma megoldására

Egy új fájlban motorcycle_adapter.py, adja hozzá a következő osztályt:

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)

Létrehoztunk egy MotorcycleAdapter osztály, amely egy szolgáltatásobjektummal példányosítja magát (motorcycle). Az illesztő azokat a kliens metódusokat valósítja meg, amelyek accelerate(), apply_brakes() és a assign_driver(). A test belsejében a accelerate() módszert alkalmaztuk motorcycle a meghívandó szolgáltatásobjektum példánya rev_throttle() szolgáltatási mód. Hasonlóképpen, a többi módszer a megfelelő metódusokat használja Motorcycle osztály.

Most frissítsük drive.py így használhatjuk az adaptert a try/except Blokk:

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()

Itt,bike_adapter tárgya a MotorcycleAdapter osztály. Mi szállítottuk a bike tiltakozik a MotorcycleAdapter osztály’ konstruktora. Ennek a szkriptnek a végrehajtása a következő kimenetet adja:

Tekintse meg gyakorlatias, gyakorlati útmutatónkat a Git tanulásához, amely tartalmazza a bevált gyakorlatokat, az iparág által elfogadott szabványokat és a mellékelt csalólapot. Hagyd abba a guglizást a Git parancsokkal, és valójában tanulni meg!

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

Anélkül, hogy módosítani kellene a mögöttes elemet Motorcycle osztályban, úgy tudjuk működni, mint a Car adapter segítségével!

Az adaptertervezési minta előnyei és hátrányai

Az adapterminták előnyei a következők:

  • Alacsony csatolást érhetünk el az adapter osztály és a kliens osztály között.
  • Az adapterosztályt újra felhasználhatjuk, hogy számos szolgáltatási osztályt beépítsünk az alkalmazásba.
  • A program rugalmasságát több adapter bevezetésével növelhetjük anélkül, hogy a kliens kódjába beleavatkoznánk

Az adapterminta hátrányai a következők:

  • A program összetettsége nő az adapterosztály és a szolgáltatási osztály hozzáadásával.
  • Növekszik a programban a többletköltség, mivel a kéréseket egyik osztályról a másikra továbbítják.
  • Az Adapter Pattern (osztályadapter) több öröklődést használ, amelyet nem biztos, hogy az összes programozási nyelv támogat.

Következtetés

Ebben a cikkben megismerkedtünk az adapter tervezési mintájával, típusaival és az általuk megoldott problémákkal. Az Adapter Pattern-et a Pythonban implementáltuk, hogy interakcióba léphessünk a Motorcycle tárgy, mint a Car objektumot egy adapter használatával, így az egyes osztályok felülete nem változik.

Időbélyeg:

Még több Stackabus