Vzorec načrtovanja adapterja v Pythonu

Predstavitev

O Vzorec zasnove adapterja je priljubljena Strukturni vzorec oblikovanja uporablja v programskem inženiringu. Ta vodnik obravnava, kako lahko implementiramo vzorec načrtovanja adapterja v Python.

Oblike oblikovanja so predloge podobne rešitve – praktično recepti za reševanje ponavljajočih se pogostih težav pri razvoju programske opreme. Vzorec adapterja temelji na konceptu adapterja iz resničnega sveta! Na primer, polnilnik prenosnega računalnika ima lahko 3-polni vtič na koncu, stenska vtičnica pa je lahko samo 2-polna vtičnica. Za priključitev 3-polnega polnilnika v to vtičnico bi potrebovali adapter, ki sprejme 3-polni vtič in prilagaja vmesnik v 2-pin vtičnica.

2-polni polnilec in 3-polni polnilec imata enako osnovno funkcijo (prevajajo elektriko iz vtičnice v prenosnik), vendar imajo drugačna oblika, in lahko enostavno prilagodijo v drugo. Kadarkoli imate komponente programske opreme z isto osnovno funkcijo, vendar različnih oblik, lahko uporabite vzorec načrtovanja adapterja.

Vzorec adapterja sledi točno temu načelu. Omogoča, da dva nezdružljiva vmesnika delujeta skupaj, ne da bi spremenili notranjost vsake komponente. To se doseže s prilagajanjem enega vmesnika drugemu navzven.

Oglejmo si nekaj osnovne terminologije, preden se poglobimo v svet vzorcev adapterjev:

  • Odjemalski vmesnik: Vmesnik, ki določa funkcije, ki naj bi jih izvajal odjemalec.
  • Pomoč: razred, ki implementira vmesnik odjemalca.
  • Adaptator/Servis: Nezdružljiv razred, ki mora sodelovati z odjemalskim vmesnikom.
  • Adapter: razred, ki omogoča sodelovanje med storitvijo in odjemalcem.

Različne vrste vzorcev adapterjev

Vzorec zasnove adapterja je mogoče implementirati na dva različna načina:

Predmetni adapter

S to metodo razred adapterja izvaja metode iz odjemalskega vmesnika. Tako sta objekt odjemalca in objekt adapterja združljiva drug z drugim. Storitveni objekt tvori a has-a odnos z objektom adapterja, tj. storitveni objekt pripada objektu adapterja.

Vemo, da servisni razred ni združljiv s stranko. Razred adapterja se ovije okoli storitvenega objekta tako, da se instancira s tem objektom. Zdaj lahko do storitvenega objekta dostopate prek objekta adapterja, kar odjemalcu omogoča interakcijo z njim.

Objektni adapter lahko implementiramo v vse sodobne programske jezike.

Razredni adapter

Pri tej metodi ima adapter is-a razmerje s servisnim razredom. V tem scenariju adapter izvaja metode, ki jih zahteva odjemalec, vendar podeduje več prilagojenih elementov, kar mu daje možnost neposrednega klica njihovih nezdružljivih funkcij. Največja pomanjkljivost te različice je, da jo lahko uporabljamo samo v programskih jezikih, ki podpirajo večkratno dedovanje razredov.

Implementacija vzorca načrtovanja adapterja v Pythonu

V spodnjem razdelku bomo implementirali oblikovalski vzorec Adapter v Python, zlasti z uporabo različica adapterja objekta. Sekcija je razdeljena na dva dela. Najprej bomo ustvarili okolje, kjer bo uporabljen vzorec adapterja. Pomembno je jasno videti, kako lahko ta vzorec reši nekatere težave s programsko opremo. Drugi del bo za rešitev težave uporabil adapter.

Težava z nezdružljivostjo med razredi

Oglejmo si vprašanje združljivosti, ko odjemalec in storitveni razred implementirata različne funkcionalnosti. Ustvarite razred odjemalca z naslednjimi metodami in ga shranite v mapo kot 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")

Tukaj smo ustvarili a Car razred s tremi metodami accelerate(), apply_brakes() in assign_driver(). Uvozili smo random modul in ga uporabil za ustvarjanje številk, ki določajo hitrost avtomobila po pospeševanju in zaviranju. The assign_driver() prikaže ime voznika avtomobila.

Nato moramo ustvariti storitveni ali prilagojeni razred, ki želi sodelovati z razredom odjemalca Car. Ustvarite razred motornih koles, kot je ta, in ga shranite v svojo mapo kot 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")  

Servisni razred, Motorcycle se ustvari zgoraj s tremi metodami rev_throttle(), pull_brake_lever()in assign_rider(). Opazite razliko med metodama storitvenega in odjemalskega razreda kljub njuni podobni funkcionalnosti. The accelerator() metoda poveča hitrost avtomobila, medtem ko rev_throttle() metoda poveča hitrost motocikla. prav tako apply_brakes() in pull_brake_lever() zavira v ustreznih vozilih. Končno, assign_driver() in assign_rider() metode dodeli upravljavcu vozila.

Nato ustvarimo razred za dostop do teh različnih metod. Najprej dodajte __init.py__ v isti mapi, ki ste jo ustvarili car.py in motorcycle.py:

touch __init__.py

Zdaj dodajte naslednjo kodo v novo datoteko 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()

Ta skript, ki ustvari naše odjemalce in storitvene objekte. Najprej uvozimo Car in Motorcycle razrede in z njimi ustvarite predmete. Nato prikličemo metode iz bike objekt (Motorcycle razred). Nato prikličemo metode car objekt (Car razred). Ko se izvede, bo delovala vsa do sedaj omenjena koda.

Vendar se pojavi izjema, ko poskušamo priklicati metode Car razred z bike predmet. Ko zaženemo ta skript:

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'

V tem primeru lahko spremenimo Motorcycle razred ali drive.py skript za uporabo pravih metod. Vendar v mnogih primerih morda nimamo dostopa do izvorne kode odjemalca ali storitvenega razreda. Tudi to je preprost primer. Pri večjih odjemalcih in storitvah morda ne bo mogoče preoblikovati nobenega od njih, če prekinemo združljivost z drugimi sistemi.

Namesto tega lahko uporabimo adapter za premostitev vrzeli v združljivosti med našo odjemalsko kodo in našim storitvenim objektom.

Uporaba adapterjev za rešitev težave z nezdružljivostjo

V novi datoteki, motorcycle_adapter.py, dodajte naslednji razred:

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)

Ustvarili smo a MotorcycleAdapter razred, ki se instancira s storitvenim objektom (motorcycle). Adapter izvaja odjemalske metode, ki so accelerate(), apply_brakes() in assign_driver(). V notranjosti telesa accelerate() metodo smo uporabili motorcycle primerek storitvenega predmeta, ki ga želite poklicati rev_throttle() način storitve. Podobno druge metode uporabljajo ustrezne metode Motorcycle razred.

Zdaj pa posodobimo drive.py tako da lahko uporabimo adapter v try/except blok:

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

Tubike_adapter je predmet MotorcycleAdapter razred. Dobavljali smo bike nasprotovati MotorcycleAdapter konstruktor razreda. Izvajanje tega skripta nam daje naslednje rezultate:

Oglejte si naš praktični, praktični vodnik za učenje Gita z najboljšimi praksami, standardi, sprejetimi v panogi, in priloženo goljufijo. Nehajte Googlati ukaze Git in pravzaprav naučiti it!

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

Brez prilagoditve osnovnega Motorcycle razreda, ga lahko pripravimo, da deluje kot a Car z uporabo adapterja!

Prednosti in slabosti vzorca načrtovanja adapterja

Prednosti vzorcev adapterjev so:

  • Dosežemo lahko nizko povezavo med razredom adapterja in razredom odjemalca.
  • Razred adapterja lahko ponovno uporabimo za vključitev številnih servisnih razredov v aplikacijo.
  • Fleksibilnost programa lahko povečamo z uvedbo več adapterjev brez poseganja v kodo odjemalca

Slabosti vzorca adapterja so:

  • Kompleksnost programa se poveča z dodatkom razreda adapterja in servisnega razreda.
  • V programu se povečajo režijski stroški, saj se zahteve posredujejo iz enega razreda v drugega.
  • Vzorec adapterja (adapter razreda) uporablja večkratno dedovanje, ki ga morda ne podpirajo vsi programski jeziki.

zaključek

V tem članku smo izvedeli več o vzorcu načrtovanja adapterja, njegovih vrstah in težavah, ki jih rešujejo. Implementirali smo vzorec adapterja v Python, tako da lahko komuniciramo z a Motorcycle predmet, kot a Car objekt z uporabo adapterja, tako da se vmesnik vsakega razreda ne spremeni.

Časovni žig:

Več od Stackabuse