Шаблон дизайну адаптера в Python

Вступ

Команда Шаблон дизайну адаптера є популярним Шаблон структурного проектування використовується в розробці програмного забезпечення. У цьому посібнику розглядається, як ми можемо реалізувати шаблон дизайну адаптера в Python.

Шаблони дизайну це шаблонні рішення – практичні рецепти для вирішення повторюваних, типових проблем у розробці програмного забезпечення. Шаблон адаптера базується на концепції реального адаптера! Наприклад, зарядний пристрій ноутбука може мати 3-контактний штекер на кінці, але настінна розетка може бути лише 2-контактним. Щоб підключити 3-контактний зарядний пристрій до цієї розетки, нам знадобиться адаптер, який приймає 3-контактний штекер, і адаптує інтерфейс у 2-штифт розетка.

Є 2-контактний зарядний пристрій і 3-контактний зарядний пристрій та сама основна функція (проводять електрику від розетки до ноутбука), але мають інша форма, і можна легко пристосовувати в інший. Якщо у вас є компоненти програмного забезпечення з однаковою базовою функцією, але різної форми, ви можете застосувати шаблон проектування адаптера.

Шаблон адаптера дотримується саме цього принципу. Це дозволяє двом несумісним інтерфейсам працювати разом без зміни внутрішньої частини кожного компонента. Це досягається шляхом зовнішньої адаптації одного інтерфейсу до іншого.

Давайте розглянемо базову термінологію, перш ніж заглибитися у світ шаблонів адаптерів:

  • Клієнтський інтерфейс: інтерфейс, який визначає функції, які клієнт повинен реалізувати.
  • Клієнт: клас, який реалізує клієнтський інтерфейс.
  • Адаптант/Сервіс: несумісний клас, якому потрібно співпрацювати з інтерфейсом клієнта.
  • Адаптер: клас, який робить можливою співпрацю між службою та клієнтом.

Різні типи шаблонів адаптерів

Шаблон проектування адаптера можна реалізувати двома різними способами:

Об'єктний адаптер

За допомогою цього методу клас адаптера реалізує методи з інтерфейсу клієнта. Таким чином, клієнтський об'єкт і адаптерний об'єкт сумісні один з одним. Об'єкт послуги утворює a has-a зв'язок з об'єктом адаптера, тобто службовий об'єкт належить об'єкту адаптера.

Ми знаємо, що клас обслуговування не сумісний з клієнтом. Клас адаптера обертається навколо службового об’єкта, створюючи екземпляр цього об’єкта. Тепер до об’єкта служби можна отримати доступ через об’єкт адаптера, що дозволяє клієнту взаємодіяти з ним.

Ми можемо реалізувати об'єктний адаптер на всіх сучасних мовах програмування.

Адаптер класу

При цьому методі адаптер має is-a відносини з класом обслуговування. У цьому сценарії адаптер реалізує методи, необхідні клієнту, але він успадковує від кількох адаптованих, що дає йому можливість безпосередньо викликати їхні несумісні функції. Найбільшим недоліком цього варіанту є те, що ми можемо використовувати його лише в мовах програмування, які підтримують множинне успадкування класів.

Реалізація шаблону дизайну адаптера в Python

У розділі нижче ми реалізуємо шаблон проектування адаптера в Python, зокрема, використовуючи варіація адаптера об'єкта. Розділ поділений на дві частини. По-перше, ми створимо середовище, де буде використовуватися шаблон адаптера. Важливо чітко бачити, як цей шаблон може вирішити деякі проблеми програмного забезпечення. У другому розділі для вирішення проблеми використовуватиметься адаптер.

Проблема несумісності між класами

Давайте розглянемо проблему сумісності, коли клієнт і клас обслуговування реалізують різні функції. Створіть клас клієнта за допомогою наведених нижче методів і збережіть його в папці як 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")

Тут ми створили a Car клас з трьома методами accelerate(), apply_brakes() та assign_driver(). Ми імпортували random і використовував його для генерації чисел, які встановлюють швидкість автомобіля після прискорення та застосування гальм. The 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(). Зверніть увагу на різницю між методами класу служби та клієнта, незважаючи на їх схожу функціональність. The 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 класи та створювати з ними об’єкти. Потім ми викликаємо методи з bike об'єкт (Motorcycle клас). Після цього ми викликаємо методи car об'єкт (Car клас). Після виконання весь згаданий код працюватиме.

Однак виникає виняток, коли ми намагаємося викликати методи 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)

Ми створили a 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 з передовими методами, прийнятими в галузі стандартами та включеною шпаргалкою. Припиніть гуглити команди 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 ми можемо змусити його працювати як a Car за допомогою адаптера!

Плюси та мінуси шаблону дизайну адаптера

Переваги шаблонів адаптерів:

  • Ми можемо досягти низького зв'язку між класом адаптера та класом клієнта.
  • Ми можемо повторно використовувати клас адаптера, щоб включити в додаток численні класи обслуговування.
  • Ми можемо підвищити гнучкість програми, ввівши кілька адаптерів без втручання в код клієнта

Недоліки Adapter Pattern:

  • Складність програми збільшується з додаванням класу адаптера та класу обслуговування.
  • У програмі збільшуються накладні витрати, оскільки запити пересилаються з одного класу в інший.
  • Шаблон адаптера (адаптер класу) використовує багаторазове успадкування, яке можуть підтримувати не всі мови програмування.

Висновок

У цій статті ми дізналися про шаблон проектування адаптера, його типи та проблеми, які вони вирішують. Ми реалізували шаблон адаптера в Python, щоб ми могли взаємодіяти з a Motorcycle об'єкт, як a Car за допомогою адаптера, щоб інтерфейс кожного класу не змінювався.

Часова мітка:

Більше від Stackabuse