الگوی طراحی آداپتور در پایتون

معرفی

La الگوی طراحی آداپتور محبوب است الگوی طراحی سازه مورد استفاده در مهندسی نرم افزار این راهنما به چگونگی پیاده سازی الگوی طراحی آداپتور در پایتون می پردازد.

الگوهای طراحی راه حل هایی شبیه به الگو هستند - عملا دستور العمل هایی برای حل مشکلات تکراری و رایج در توسعه نرم افزار. الگوی آداپتور بر اساس مفهوم آداپتور دنیای واقعی است! به عنوان مثال، شارژر لپ تاپ ممکن است یک دوشاخه 3 پین در انتهای آن داشته باشد، اما پریز دیواری ممکن است فقط یک سوکت 2 پین باشد. برای وصل کردن یک شارژر 3 پین به این پریز، به یک آداپتور نیاز داریم که یک دوشاخه 3 پین را بپذیرد، و تطبیق می دهد رابط به 2 پین سوکت

یک شارژر 2 پین و یک شارژر 3 پین دارند همان عملکرد اصلی (الکتریسیته را از سوکت به لپ تاپ منتقل کنید)، اما داشته باشید یک فرم متفاوت، و شخص به راحتی می تواند وفق دادن به دیگری هر زمان که اجزای نرم افزاری با عملکرد اصلی یکسان اما اشکال متفاوت دارید، می توانید الگوی طراحی آداپتور را اعمال کنید.

الگوی آداپتور دقیقاً از این اصل پیروی می کند. این اجازه می دهد تا دو اینترفیس ناسازگار با یکدیگر بدون تغییر اجزای داخلی هر جزء کار کنند. این با تطبیق یک رابط، به دیگری، به صورت خارجی به دست می آید.

بیایید قبل از غواصی عمیق تر به دنیای الگوهای آداپتور، به برخی اصطلاحات اساسی نگاه کنیم:

  • رابط مشتری: رابطی که توابعی را که کلاینت باید پیاده سازی کند را مشخص می کند.
  • مشتری: کلاسی که رابط مشتری را پیاده سازی می کند.
  • سازگار/خدمات: کلاس ناسازگاری که نیاز به همکاری با رابط مشتری دارد.
  • آداپتور: کلاسی که همکاری بین سرویس و مشتری را ممکن می کند.

انواع مختلف الگوهای آداپتور

الگوی طراحی آداپتور را می توان به دو روش مختلف پیاده سازی کرد:

آداپتور شی

با این روش، کلاس آداپتور متدها را از رابط مشتری پیاده سازی می کند. بنابراین، شی مشتری و شی آداپتور با یکدیگر سازگار هستند. شیء سرویس a را تشکیل می دهد has-a رابطه با شی آداپتور یعنی شیء سرویس متعلق به شی آداپتور است.

ما می دانیم که کلاس خدمات با مشتری سازگار نیست. کلاس آداپتور با نمونه سازی خود با آن شی، در اطراف شیء سرویس می پیچد. اکنون، شیء سرویس از طریق شیء آداپتور قابل دسترسی است و به مشتری امکان می دهد با آن تعامل داشته باشد.

ما می توانیم شی آداپتور را در تمام زبان های برنامه نویسی مدرن پیاده سازی کنیم.

آداپتور کلاس

با این روش، آداپتور دارای یک is-a ارتباط با کلاس خدمات در این سناریو، آداپتور متدهای مورد نیاز مشتری را پیاده‌سازی می‌کند، اما از چندین سازگار به ارث می‌برد و به آن توانایی فراخوانی مستقیم توابع ناسازگار آنها را می‌دهد. بزرگترین اشکال این تنوع این است که ما فقط می توانیم از آن در زبان های برنامه نویسی استفاده کنیم که از وراثت چندگانه کلاس ها پشتیبانی می کنند.

پیاده سازی الگوی طراحی آداپتور در پایتون

در بخش زیر، الگوی طراحی آداپتور را در پایتون پیاده سازی می کنیم، به طور خاص با استفاده از تنوع آداپتور شی. بخش به دو بخش تقسیم می شود. ابتدا محیطی را ایجاد می کنیم که از الگوی آداپتور استفاده شود. مهم است که به وضوح ببینید این الگو چگونه می تواند برخی از مشکلات نرم افزاری را حل کند. بخش دوم از یک آداپتور برای حل مشکل استفاده می کند.

مشکل ناسازگاری بین کلاس ها

بیایید به مسئله سازگاری زمانی که کلاس سرویس گیرنده و سرویس عملکردهای مختلف را پیاده سازی می کنند، نگاه کنیم. یک کلاس کلاینت با روش های زیر ایجاد کنید و آن را در یک پوشه به عنوان ذخیره کنید 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")

در اینجا، ما ایجاد کرده ایم Car کلاس با سه روش accelerate(), apply_brakes() و assign_driver(). ما وارد کردیم random ماژول و از آن برای تولید اعدادی استفاده کرد که پس از شتاب گیری و ترمز کردن، سرعت خودرو را تعیین می کند. این assign_driver() متد نام راننده ماشین را نشان می دهد.

در مرحله بعد، ما باید یک کلاس سرویس یا سازگار ایجاد کنیم که مایل به همکاری با کلاس مشتری است Car. یک کلاس موتور سیکلت مانند این ایجاد کنید و آن را در پوشه خود ذخیره کنید 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")  

یک کلاس خدماتی، Motorcycle در بالا با سه روش ایجاد شده است rev_throttle(), pull_brake_lever()و assign_rider(). به تفاوت بین متدهای کلاس سرویس و کلاینت با وجود عملکرد مشابه آنها توجه کنید. این accelerator() روش افزایش سرعت خودرو در حالی که rev_throttle() روشی که باعث افزایش سرعت موتور سیکلت می شود. به همین ترتیب، apply_brakes() و pull_brake_lever() در وسایل نقلیه مربوطه ترمز می کند. در نهایت، assign_driver() و assign_rider() روش ها اپراتور خودرو را تعیین می کند.

در مرحله بعد، بیایید یک کلاس برای دسترسی به این متدهای مختلف ایجاد کنیم. ابتدا یک عدد را اضافه کنید __init.py__ در همان پوشه ای که ایجاد کردید car.py و motorcycle.py:

touch __init__.py

حالا کد زیر را در یک فایل جدید اضافه کنید 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()

این اسکریپت که اشیاء مشتری و سرویس ما را ایجاد می کند. ما ابتدا وارد می کنیم Car و Motorcycle کلاس ها و ایجاد اشیاء با آنها. سپس متدها را از the فراخوانی می کنیم bike هدف - شی (Motorcycle کلاس). پس از آن، ما متدهای را فراخوانی می کنیم car هدف - شی (Car کلاس). وقتی اجرا شد، تمام کدهایی که تا به حال ذکر شد کار خواهند کرد.

با این حال، زمانی که ما سعی می کنیم از روش های the استفاده کنیم، یک استثنا مطرح می شود Car کلاس با bike هدف - شی. وقتی این اسکریپت را اجرا می کنیم:

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'

در این صورت می‌توانیم آن را اصلاح کنیم Motorcycle کلاس یا drive.py اسکریپت برای استفاده از روش های مناسب. با این حال، در بسیاری از موارد، ممکن است به کد منبع مشتری یا کلاس سرویس دسترسی نداشته باشیم. همچنین، این یک مثال ساده است. با مشتریان و سرویس‌های بزرگ‌تر، ممکن است در صورت شکستن سازگاری با سایر سیستم‌ها، اصلاح هر یک از آنها امکان‌پذیر نباشد.

در عوض، می‌توانیم از یک آداپتور برای پر کردن شکاف سازگاری بین کد مشتری و شیء سرویس خود استفاده کنیم.

استفاده از آداپتورها برای حل مشکل ناسازگاری

در یک فایل جدید، motorcycle_adapter.py، کلاس زیر را اضافه کنید:

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)

ما ایجاد کردیم MotorcycleAdapter کلاس، که خود را با یک شیء سرویس (motorcycle). آداپتور متدهای کلاینت را پیاده سازی می کند accelerate(), apply_brakes() و assign_driver(). داخل بدنه accelerate() روش، ما استفاده کرده ایم motorcycle نمونه ای از شی سرویس برای فراخوانی rev_throttle() روش سرویس به همین ترتیب، روش های دیگر از روش های مربوطه استفاده می کنند Motorcycle کلاس.

حالا بیایید به روز کنیم drive.py بنابراین ما می توانیم از آداپتور در try/except مسدود کردن:

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

در اینجا،bike_adapter یک شی از MotorcycleAdapter کلاس ما عرضه کردیم bike اعتراض به MotorcycleAdapter سازنده کلاس اجرای این اسکریپت خروجی زیر را به ما می دهد:

راهنمای عملی و عملی ما برای یادگیری Git را با بهترین روش ها، استانداردهای پذیرفته شده در صنعت و برگه تقلب شامل بررسی کنید. دستورات Google Git را متوقف کنید و در واقع یاد گرفتن آی تی!

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

بدون نیاز به تنظیم زیربنا Motorcycle کلاس، ما می توانیم آن را به کار مانند یک Car با استفاده از آداپتور!

مزایا و معایب الگوی طراحی آداپتور

مزایای الگوهای آداپتور عبارتند از:

  • ما می توانیم به جفت کم بین کلاس آداپتور و کلاس مشتری دست یابیم.
  • ما می‌توانیم از کلاس آداپتور برای گنجاندن کلاس‌های خدمات متعدد در برنامه استفاده مجدد کنیم.
  • می‌توانیم با معرفی چند آداپتور بدون تداخل با کد کلاینت، انعطاف‌پذیری برنامه را افزایش دهیم

معایب الگوی آداپتور عبارتند از:

  • پیچیدگی برنامه با اضافه شدن کلاس آداپتور و کلاس سرویس افزایش می یابد.
  • با ارسال درخواست ها از یک کلاس به کلاس دیگر، هزینه های سربار در برنامه افزایش می یابد.
  • الگوی آداپتور (آداپتور کلاس) از چندین وراثت استفاده می کند که ممکن است همه زبان های برنامه نویسی از آن پشتیبانی نکنند.

نتیجه

در این مقاله با الگوی طراحی آداپتور، انواع آن و مشکلات حل آنها آشنا شدیم. ما الگوی Adapter را در پایتون پیاده سازی کردیم تا بتوانیم با a تعامل داشته باشیم Motorcycle شیء، مانند a Car با استفاده از یک آداپتور شیء کنید تا رابط هر کلاس تغییر نکند.

تمبر زمان:

بیشتر از Stackabuse