Адаптер (Adapter)
Адаптер — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Он действует как мост между двумя классами, преобразуя интерфейс одного класса в интерфейс, ожидаемый клиентом.
Основные принципы
Адаптер оборачивает объект с несовместимым интерфейсом и переводит его вызовы в вызовы, понятные целевому объекту. Выделяют два типа адаптеров: - Адаптер объекта (использует композицию). - Адаптер класса (использует множественное наследование).
Математическая формулировка
Для преобразования данных от адаптируемого класса к целевому интерфейсу используется функция маппинга:
\[
TargetMethod(args) \rightarrow AdapteeMethod(Transform(args))
\]
Блок-схема
sequenceDiagram
participant Client
participant Adapter
participant Adaptee
Client->>Adapter: request()
Adapter->>Adapter: специфическая логика адаптации
Adapter->>Adaptee: specific_request()
Adaptee-->>Adapter: результат
Adapter-->>Client: результат в формате Target
Пример реализации на Python
Рассмотрим интеграцию старой платежной системы в новый интерфейс обработки платежей.
from abc import ABC, abstractmethod
# Целевой интерфейс, который ожидает клиент
class PaymentProcessor(ABC):
@abstractmethod
def pay(self, amount: float) -> None:
pass
# Старая система с несовместимым интерфейсом
class LegacyPaymentSystem:
def make_payment(self, dollars: int, cents: int) -> None:
print(f"Оплата через Legacy систему: {dollars} долларов и {cents} центов")
# Адаптер для старой системы
class LegacyPaymentAdapter(PaymentProcessor):
def __init__(self, legacy_system: LegacyPaymentSystem):
self.legacy_system = legacy_system
def pay(self, amount: float) -> None:
# Преобразование float в формат dollars/cents
dollars = int(amount)
cents = int((amount - dollars) * 100)
self.legacy_system.make_payment(dollars, cents)
# Новая система, совместимая с целевым интерфейсом
class ModernPaymentSystem(PaymentProcessor):
def pay(self, amount: float) -> None:
print(f"Оплата через Modern систему: {amount:.2f} USD")
# Клиентский код
def process_payment(processor: PaymentProcessor, amount: float):
processor.pay(amount)
if __name__ == "__main__":
modern_system = ModernPaymentSystem()
legacy_system = LegacyPaymentSystem()
# Оборачиваем старую систему в адаптер
legacy_adapter = LegacyPaymentAdapter(legacy_system)
print("Используем Modern систему:")
process_payment(modern_system, 123.45)
print("\nИспользуем Legacy систему через адаптер:")
process_payment(legacy_adapter, 123.45)
Достоинства и недостатки
Достоинства:
- Реусинг существующего кода: Позволяет использовать классы, интерфейс которых не соответствует текущим требованиям, без изменения их исходного кода.
- Принцип открытости/закрытости: Можно вводить новые адаптеры без изменения клиентского кода.
- Разделение ответственности: Скрывает от клиента细节 преобразования интерфейсов.
Недостатки:
- Усложнение кода: Введение дополнительных классов может запутать архитектуру.