Sovittimen suunnittelumalli Pythonissa

esittely

- Sovittimen suunnittelukuvio On suosittu Rakennesuunnittelumalli käytetään ohjelmistosuunnittelussa. Tässä oppaassa tarkastellaan, kuinka voimme toteuttaa sovittimen suunnittelumallin Pythonissa.

Suunnittelumalleja ovat mallipohjaisia ​​ratkaisuja – käytännössä reseptejä ohjelmistokehityksen toistuvien, yleisten ongelmien ratkaisemiseen. Adapter Pattern perustuu todellisen sovittimen konseptiin! Esimerkiksi kannettavan tietokoneen laturin päässä voi olla 3-nastainen pistoke, mutta pistorasia voi olla vain 2-nastainen. 3-nastaisen laturin kytkemiseksi tähän pistorasiaan tarvitsemme sovittimen, joka hyväksyy 3-nastaisen pistokkeen ja mukautuu käyttöliittymä osaksi 2-pin pistorasia.

2-nastainen laturi ja 3-nastainen laturi ovat sama perustoiminto (johtaa sähköä pistorasiasta kannettavaan tietokoneeseen), mutta on eri muoto, ja voi helposti sopeuttaa toiseen. Aina kun sinulla on ohjelmistokomponentteja, joilla on sama perustoiminto, mutta eri muodot, voit käyttää sovittimen suunnittelumallia.

Sovitinmalli noudattaa juuri tätä periaatetta. Se mahdollistaa kahden yhteensopimattoman rajapinnan työskentelyn yhdessä ilman, että kunkin komponentin sisäisiä osia muokataan. Tämä saavutetaan mukauttamalla yksi käyttöliittymä toiseen, ulkoisesti.

Katsotaanpa perusterminologiaa ennen kuin sukeltaa syvemmälle Adapter Patterns -maailmaan:

  • Asiakaskäyttöliittymä: Käyttöliittymä, joka määrittää toiminnot, jotka asiakkaan tulee toteuttaa.
  • Asiakas: Luokka, joka toteuttaa asiakasrajapinnan.
  • Sopeutuja/palvelu: Yhteensopimaton luokka, jonka on tehtävä yhteistyötä asiakasliittymän kanssa.
  • Sovitin: Luokka, joka mahdollistaa palvelun ja asiakkaan välisen yhteistyön.

Erityyppiset sovitinmallit

Sovittimen suunnittelukuvio voidaan toteuttaa kahdella eri tavalla:

Kohdesovitin

Tällä menetelmällä sovitinluokka toteuttaa menetelmät asiakasliittymästä. Siten asiakasobjekti ja sovitinobjekti ovat yhteensopivia keskenään. Palveluobjekti muodostaa a has-a suhde sovitinobjektiin eli palveluobjekti kuuluu sovitinobjektiin.

Tiedämme, että palveluluokka ei ole yhteensopiva asiakkaan kanssa. Sovitinluokka kiertyy palveluobjektin ympärille instantoimalla itsensä kyseisellä objektilla. Nyt palveluobjektia voidaan käyttää sovitinobjektin kautta, jolloin asiakas voi olla vuorovaikutuksessa sen kanssa.

Pystymme toteuttamaan objektisovittimen kaikilla nykyaikaisilla ohjelmointikielillä.

Luokan sovitin

Tällä menetelmällä sovittimessa on is-a suhde palveluluokkaan. Tässä skenaariossa sovitin toteuttaa asiakkaan vaatimat menetelmät, mutta se perii useilta sovittajilta, jolloin se voi kutsua heidän yhteensopimattomia toimintojaan suoraan. Tämän muunnelman suurin haittapuoli on, että voimme käyttää sitä vain ohjelmointikielissä, jotka tukevat useiden luokkien periytymistä.

Adapter Design Patternin käyttöönotto Pythonissa

Alla olevassa osiossa toteutamme sovittimen suunnittelumallin Pythonissa, erityisesti käyttämällä objektisovittimen muunnelma. Osio on jaettu kahteen osaan. Ensin luomme ympäristön, jossa sovitinmallia tulisi käyttää. On tärkeää nähdä selvästi, kuinka tämä malli voi ratkaista joitain ohjelmisto-ongelmia. Toinen osa käyttää sovitinta ongelman ratkaisemiseen.

Luokkien välinen yhteensopimattomuusongelma

Katsotaanpa yhteensopivuusongelmaa, kun asiakas ja palveluluokka toteuttavat erilaisia ​​toimintoja. Luo asiakasluokka seuraavilla tavoilla ja tallenna se kansioon nimellä 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")

Täällä olemme luoneet a Car luokka kolmella menetelmällä accelerate(), apply_brakes() ja assign_driver(). Toimme maahan random moduuli ja käyttää sitä luomaan numeroita, jotka määrittävät auton nopeuden kiihdytyksen ja jarrutuksen jälkeen. The assign_driver() menetelmä näyttää auton kuljettajan nimen.

Seuraavaksi meidän on luotava palvelu- tai adaptee-luokka, joka haluaa tehdä yhteistyötä asiakasluokan kanssa Car. Luo tällainen moottoripyöräluokka ja tallenna se kansioon nimellä 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")  

Palveluluokka, Motorcycle on luotu yllä kolmella menetelmällä rev_throttle(), pull_brake_lever()ja assign_rider(). Huomaa ero palvelun ja asiakasluokan menetelmien välillä niiden samanlaisesta toimivuudesta huolimatta. The accelerator() menetelmä lisää auton nopeutta samalla kun rev_throttle() menetelmä lisää moottoripyörän nopeutta. Samoin apply_brakes() ja pull_brake_lever() käyttää jarruja vastaavissa ajoneuvoissa. Lopuksi, assign_driver() ja assign_rider() menetelmät osoittavat ajoneuvon kuljettajan.

Luodaan seuraavaksi luokka näitä eri menetelmiä varten. Lisää ensin an __init.py__ samassa luomassasi kansiossa car.py ja motorcycle.py:

touch __init__.py

Lisää nyt seuraava koodi uuteen tiedostoon 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()

Tämä komentosarja, joka luo asiakas- ja palveluobjektit. Tuomme ensin Car ja Motorcycle luokkia ja luoda niiden avulla objekteja. Sitten vedämme menetelmiä osoitteesta bike esine (Motorcycle luokka). Sen jälkeen vedotaan menetelmiin car esine (Car luokka). Kun se suoritetaan, kaikki tähän mennessä mainitut koodit toimivat.

Poikkeus syntyy kuitenkin, kun yritämme vedota menetelmiin Car luokan kanssa bike esine. Kun suoritamme tämän skriptin:

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'

Tässä tapauksessa voimme muokata Motorcycle luokka tai drive.py skripti käyttää oikeita menetelmiä. Monissa tapauksissa meillä ei kuitenkaan välttämättä ole pääsyä asiakkaan tai palveluluokan lähdekoodiin. Lisäksi tämä on yksinkertainen esimerkki. Suuremmilla asiakkailla ja palveluilla ei ehkä ole mahdollista heijastaa kumpaakaan uudelleen, jos yhteensopivuus muiden järjestelmien kanssa katkeaisi.

Sen sijaan voimme käyttää sovitinta umpeen yhteensopivuusaukon asiakaskoodimme ja palveluobjektimme välillä.

Sovittimien käyttäminen yhteensopivuusongelman ratkaisemiseen

Uudessa tiedostossa motorcycle_adapter.py, lisää seuraava luokka:

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)

Olemme luoneet a MotorcycleAdapter luokka, joka instantoi itsensä palveluobjektilla (motorcycle). Sovitin toteuttaa asiakasmenetelmät, jotka ovat accelerate(), apply_brakes() ja assign_driver(). Rungon sisällä accelerate() menetelmää, olemme käyttäneet motorcycle kutsuttavan palveluobjektin esiintymä rev_throttle() palvelutapa. Samoin muut menetelmät käyttävät vastaavia menetelmiä Motorcycle luokka.

Nyt päivitetään drive.py jotta voimme käyttää sovitinta try/except lohko:

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

Täälläbike_adapter on kohde MotorcycleAdapter luokkaa. Toimitimme bike vastustaa MotorcycleAdapter luokan rakentaja. Tämän skriptin suorittaminen antaa meille seuraavan tuloksen:

Tutustu käytännönläheiseen, käytännölliseen Gitin oppimisoppaaseemme, jossa on parhaat käytännöt, alan hyväksymät standardit ja mukana tuleva huijauslehti. Lopeta Git-komentojen googlailu ja oikeastaan oppia se!

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

Ilman, että taustaa tarvitsee säätää Motorcycle luokassa, voimme saada sen toimimaan kuten a Car adapterilla!

Adapterin suunnittelumallin plussat ja miinukset

Adapterimallien edut ovat:

  • Voimme saavuttaa matalan kytkennän sovitinluokan ja asiakasluokan välillä.
  • Voimme käyttää sovitinluokkaa uudelleen useiden palveluluokkien sisällyttämiseksi sovellukseen.
  • Voimme lisätä ohjelman joustavuutta ottamalla käyttöön useita sovittimia häiritsemättä asiakaskoodia

Adapter Patternin haitat ovat:

  • Ohjelman monimutkaisuus lisääntyy, kun sovitinluokka ja palveluluokka lisätään.
  • Ohjelman yleiskustannukset kasvavat, kun pyynnöt välitetään luokasta toiseen.
  • Adapter Pattern (luokkasovitin) käyttää useita perintöjä, joita kaikki ohjelmointikielet eivät välttämättä tue.

Yhteenveto

Tässä artikkelissa opimme sovittimen suunnittelumallista, sen tyypeistä ja niiden ratkaisemista ongelmista. Otimme sovitinmallin käyttöön Pythonissa, jotta voimme olla vuorovaikutuksessa a Motorcycle esine, kuten a Car objekti sovittimen avulla, jotta kunkin luokan käyttöliittymä ei muutu.

Aikaleima:

Lisää aiheesta Stackabus