Патерн адаптер відноситься до структурних патернів і потрібен для того, аби зробити можливою роботу двох несумісних систем без переписування жодної з них.
Якщо вам потрібна асоціація, то “впіхнуть нєвпіхуємоє” може бути гарною.
Приклад з життя
Гарним прикладом може бути ситуація. Уявіть, ви сидите в барі, раптом бачите привабливого хлопця за сусіднім столом. Наважуєтесь до нього підійти і заговорити… Але розумієте що він говорить лише французькою. А ви ні. Які у нас є опції?
- Вивчити французьку;
- Знайти іншого співрозмовника. А якщо жоден не підходить, можна взяти телефон, ввімкнути перекладач і косо-криво поговорити кожен своєю мовою.
Перекладач в цьому випадку відіграють роль адаптера. Його використання дозволило вам вирішити проблему не міняючи ні співрозмовника ні вас.
Відповідно, якби ми програмували такий приклад, це б мало десь такий вигляд:
<?php
class UkrainianGuy
{
public function say(string $message): string
{
return $message;
}
}
class FrenchGuy
{
public function dire(string $message): string
{
return $message;
}
}
interface ConversationInterface
{
public function say(string $message): string;
}
class GoogleTranslateAdapter implements ConversationInterface
{
public function __construct(
private FrenchGuy $frenchGuy
) {}
public function say(string $message): string
{
$translated = $this->translateToFrench($message);
return $this->frenchGuy->dire($translated);
}
private function translateToFrench(string $message): string
{
return "*(перекладено французькою)*: " . $message;
}
}
// --- Використання ---
$ukrainianGuy = new UkrainianGuy();
$frenchGuy = new FrenchGuy();
$translator = new GoogleTranslateAdapter($frenchGuy);
$message = $ukrainianGuy->say("Привіт! Ти тут один?");
echo $translator->say($message);
Ролі:
UkrainianGuy — клієнт. Той, хто ініціює спілкування. Не змінюється
FrenchGuy — adaptee (той, кого адаптують). Існуючий клас з несумісним інтерфейсом. Теж не змінюється
ConversationInterface — цільовий інтерфейс. Те, як клієнт хоче спілкуватись — через say()
GoogleTranslateAdapter — власне адаптер. Реалізує ConversationInterface, але всередині делегує виклик до FrenchGuy::dire()
Коли використовувати?
Коли є два класи, які мають працювати разом, але мають несумісні інтерфейси - і жоден з них змінювати не можна або не хочеться. Наприклад, підключаєш сторонню бібліотеку або легасі-код, який вже написаний і працює, але його інтерфейс не збігається з тим, що очікує твій код.