Ответ
Паттерн Адаптер (Adapter) — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Он выступает в роли обертки, преобразуя интерфейс одного класса (адаптируемого объекта, или adaptee) в интерфейс, ожидаемый клиентом (целевой интерфейс, или target).
Назначение: Основная цель Адаптера — обеспечить взаимодействие между классами, которые не могут работать вместе напрямую из-за несовместимости их интерфейсов, без изменения исходного кода этих классов.
Типы Адаптеров:
- Адаптер объекта (Object Adapter): Использует композицию. Адаптер содержит экземпляр адаптируемого объекта и делегирует ему вызовы, преобразуя их. Это наиболее распространенный подход в Python.
- Адаптер класса (Class Adapter): Использует множественное наследование (если язык поддерживает). Адаптер наследует как от целевого интерфейса, так и от адаптируемого класса. В Python менее применим из-за особенностей наследования и предпочтения композиции.
Пример (Object Adapter на Python):
Представим, что у нас есть старая система логирования, которая принимает сообщения только через метод log_message_old_format, а новая система ожидает метод log_message.
# Адаптируемый класс (Adaptee) - старая система
class OldLogger:
def log_message_old_format(self, message: str):
print(f"[OLD LOG]: {message}")
# Целевой интерфейс (Target) - что ожидает клиент
class NewLoggerInterface:
def log_message(self, message: str):
raise NotImplementedError("Должен быть реализован подклассом")
# Адаптер (Adapter)
class LoggerAdapter(NewLoggerInterface):
def __init__(self, old_logger: OldLogger):
self._old_logger = old_logger
def log_message(self, message: str):
# Преобразуем вызов нового интерфейса в вызов старого
self._old_logger.log_message_old_format(f"[ADAPTED] {message}")
# Клиентский код, который работает с новым интерфейсом
def client_code(logger: NewLoggerInterface, text: str):
logger.log_message(text)
# Использование:
old_logger_instance = OldLogger()
# Клиент не может напрямую использовать OldLogger:
# client_code(old_logger_instance, "Это сообщение не сработает") # Ошибка атрибута
# Используем адаптер для совместимости
adapter = LoggerAdapter(old_logger_instance)
client_code(adapter, "Сообщение через адаптер")
# Вывод:
# [OLD LOG]: [ADAPTED] Сообщение через адаптер
Когда использовать паттерн Адаптер?
- Интеграция: Когда нужно использовать существующий класс, но его интерфейс не соответствует потребностям.
- Сторонние библиотеки: При работе с библиотеками, которые имеют полезную функциональность, но неудобный или несовместимый API.
- Унификация: Для предоставления единого интерфейса к нескольким классам с похожей, но не идентичной функциональностью.
Преимущества:
- Повторное использование кода: Позволяет использовать существующие классы без их модификации.
- Разделение ответственности: Отделяет логику преобразования интерфейсов от основной бизнес-логики.
- Гибкость: Позволяет легко заменять адаптируемые классы, не затрагивая клиентский код.
Недостатки:
- Увеличение сложности: Добавляет новые классы, что может усложнить структуру проекта.
- Производительность: Небольшие накладные расходы из-за дополнительного уровня абстракции (обычно незначительные).
Ответ 18+ 🔞
А, паттерн Адаптер, говоришь? Ну это ж классика, блядь, ёпта! Представь себе ситуацию, ну прям как в жизни, сука.
Вот есть у тебя, допустим, старый, блядь, советский штепсель — этакий здоровый, с толстыми ногами. А розетка у тебя новая, европейская, с этими, блядь, дырочками тоненькими. И ты такой: "Ну какого хуя?" Ты ж не будешь стену ломать, розетку менять или, того хуже, вилку зубилом обтачивать, блядь! Ты берёшь переходничок, эту самую, сука, прокладку между мирами — и вот он, твой Адаптер, нахуй! Вставил старую вилку в одну сторону, а другую — в новую розетку, и свет загорелся, пиздец!
Так и в коде, блядь. Есть у тебя какая-нибудь старая библиотека, написанная ещё когда трава была зеленее, с методами типа log_message_old_format(). А ты уже всю новую систему построил вокруг красивого интерфейса NewLoggerInterface.log_message(). И что, переписывать старую библиотеку, на которую завязано пол-проекта? Да хуй там! Напрягись, жопа с ручками, и сделай Адаптер!
Смотри, как это выглядит, только не пугайся, код оставляю как есть, он правильный:
# Это наш старый дед, Adaptee. Говорит на своём языке.
class OldLogger:
def log_message_old_format(self, message: str):
print(f"[OLD LOG]: {message}")
# А это то, на чём говорит весь наш новый шикарный район, Target.
class NewLoggerInterface:
def log_message(self, message: str):
raise NotImplementedError("Должен быть реализован подклассом")
# А вот и наш переводчик-приспособленец, сам Адаптер!
class LoggerAdapter(NewLoggerInterface):
def __init__(self, old_logger: OldLogger):
self._old_logger = old_logger # Засунули старика в карман
def log_message(self, message: str):
# А тут магия: берём новый вызов и конвертим в старый.
self._old_logger.log_message_old_format(f"[ADAPTED] {message}")
# Клиентский код — он избалованный, общается только на новом языке.
def client_code(logger: NewLoggerInterface, text: str):
logger.log_message(text)
# Поехали, сука!
old_logger_instance = OldLogger()
# Прямой вызов — облом. Клиент тупо не поймёт старика.
# client_code(old_logger_instance, "Не сработает") # Вылетит с ошибкой, как пробка!
# А вот так — красота! Даём клиенту нашего переводчика.
adapter = LoggerAdapter(old_logger_instance)
client_code(adapter, "Сообщение через адаптер")
# На выходе получим:
# [OLD LOG]: [ADAPTED] Сообщение через адаптер
Видишь? Клиенту похуй, кто там внутри — старый пень или нейросеть. Ему главное, чтобы метод log_message был. А адаптер, этот хитрожопый посредник, берёт вызов, немножко его облизывает, подготавливает и суёт старику, который делает свою работу. Всё довольны, мир во всём мире, ебать мои старые костыли!
Когда это впихивать в проект? Да когда угодно, блядь! Когда подключаешь левую библиотеку, от которой воняет нафталином. Когда два модуля друг на друга криво смотрят и не могут договориться. Когда нужно сделать единую рожу для кучи разных классов, которые делают одно и то же, но называют это разными словами.
Плюсы, минусы? Плюс — не надо ломать работающий код, можно повторно использовать старый хлам. Минус — появляется ещё один слой, эти ваши абстракции, за которыми надо следить. Но это, как говорится, овердохуища лучше, чем перелопачивать тонны legacy-кода. Короче, паттерн как таблетка от головной боли при интеграции. Выпей — и живи спокойно.