Ответ
В гексагональной архитектуре (Ports and Adapters) адаптер — это компонент, который соединяет ядро приложения (бизнес-логику) с внешним миром.
Его главная задача — преобразовывать данные и вызовы между ядром и внешними системами (UI, база данных, сторонние API), изолируя бизнес-логику от деталей их реализации.
Существует два типа адаптеров:
-
Управляющие (первичные) адаптеры (Driving Adapters): Принимают ввод от пользователя или внешних систем и вызывают ядро приложения. Примеры: контроллеры в веб-фреймворке (REST API), обработчики CLI-команд.
-
Управляемые (вторичные) адаптеры (Driven Adapters): Вызываются ядром приложения для взаимодействия с внешними сервисами. Примеры: репозиторий для работы с базой данных, клиент для отправки email.
Пример (порт и адаптер для БД на Python):
# 1. Порт (интерфейс), определяемый ядром приложения
class UserRepositoryPort:
def save(self, user: User) -> None:
raise NotImplementedError
# 2. Вторичный адаптер, реализующий порт для конкретной БД
class PostgresUserRepositoryAdapter(UserRepositoryPort):
def __init__(self, db_connection):
self.db = db_connection
def save(self, user: User) -> None:
# Логика преобразования доменной модели в формат БД и сохранения
print(f"Сохранение пользователя {user.name} в PostgreSQL...")
query = "INSERT INTO users (id, name) VALUES (%s, %s)"
self.db.execute(query, (user.id, user.name))
Таким образом, адаптеры позволяют заменять внешние компоненты (например, перейти с PostgreSQL на MongoDB), не затрагивая бизнес-логику ядра. Достаточно лишь реализовать новый адаптер.
Ответ 18+ 🔞
А, слушай, вот эта ваша гексагональная архитектура, блядь! Ну, про порты и адаптеры. Это ж, ёпта, как в жизни: чтобы мозг твой, то есть ядро приложения, не засирали всякой хуйнёй типа баз данных или этих ваших API.
Адаптер — это такой переводчик-хуеврёт, понимаешь? Сидит на границе и орёт: «Ядро, тут тебе данные принесли, но они в JSON, блядь!» А ядро ему: «Да похуй, мне в объектах давай!» И он берёт, и переводит. И наоборот: ядро говорит «Сохрани эту сущность», а адаптер бежит к базе и орет уже на её языке: «INSERT, блядь, делай!»
Их, этих адаптеров, два вида, как два сраных сортира:
-
Управляющие (Driving). Это те, кто лезет к ядру первым. Как назойливый клиент или пользователь в интерфейсе. Контроллер в REST API — вот он, классический управляющий адаптер. Приполз, получил HTTP-запрос, отпиздовал его в нормальный вызов метода ядра.
-
Управляемые (Driven). А это те, кого ядро само дёргает, когда ему что-то надо. Типа холопы. «Эй, репозиторий, сохрани-ка мне это!» — орет ядро. А репозиторий — он и есть адаптер, блядь — бежит в базу данных и там уже сам разбирается, в какую таблицу и какую хуйню писать.
Смотри, вот тебе пример, чтобы вообще пиздец как понятно стало. Допустим, ядру нужно сохранять пользователей. Оно не будет, блядь, SQL-запросы писать — это же унизительно для бизнес-логики!
# 1. Это порт, или, грубо говоря, объявление намерений от ядра.
# Ядро заявляет: "Слушай, мир, я хочу сохранять пользователей через вот такой метод!"
# А как ты это сделаешь — твои проблемы, мне похуй.
class UserRepositoryPort:
def save(self, user: User) -> None:
raise NotImplementedError
# 2. А вот это уже адаптер — конкретный пацан, который выполняет приказ.
# Он реализует тот самый порт, но для PostgreSQL.
# Видишь? Он знает про connection, про SQL, про таблицы. А ядро про эту хуйню не знает и знать не хочет!
class PostgresUserRepositoryAdapter(UserRepositoryPort):
def __init__(self, db_connection):
self.db = db_connection
def save(self, user: User) -> None:
# Вот тут магия преобразования: доменный объект User -> строки для SQL.
print(f"Сохранение пользователя {user.name} в PostgreSQL...")
query = "INSERT INTO users (id, name) VALUES (%s, %s)"
self.db.execute(query, (user.id, user.name))
И вся соль, блядь, в чём? Захотел ты завтра вместо PostgreSQL использовать MongoDB, потому что начальник прочитал статью на Хабре. Ну и хуй с ним! Ты не лезешь в святое — в ядро. Ты просто пишешь нового холопа, MongoUserRepositoryAdapter, который тоже реализует UserRepositoryPort, но внутри орёт уже на языке MongoDB. Подсовываешь его ядру вместо постгресовского — и ядро даже не заметит подмены, ебать его в сраку! Оно как кричало «сохрани!», так и продолжает. А там уж новый адаптер сам разберётся, как это в монге сделать.
Вот и вся философия, блядь. Изоляция, епта. Чтобы бизнес-логика жила в своём уютном мирке и не парилась, что там во внешнем мире творится — революция, смена базы данных или новый фреймворк. Ей похуй.