===== Адаптер (Adapter / Wrapper) ===== Шаблон адаптера позволяет обернуть несовместимый объект в адаптер, чтобы сделать его совместимым с другим классом. Чаще всего "Адаптер" применяется, если необходимо создать определенный класс, производный от уже существующего. Привести нестандартный или неудобный интерфейс какого-то класса в интерфейс, совместимый с вашим кодом. Адаптер\\ позволяет классам работать вместе стандартным образом, что обычно не получается из-за несовместимых интерфейсов,\\ предоставляя для этого прослойку с интерфейсом, удобным для клиентов, самостоятельно используя оригинальный интерфейс. **Использование:** * Когда вы хотите использовать сторонний класс, но его интерфейс не соответствует остальному коду приложения. * Когда вам нужно использовать несколько существующих подклассов, но в них не хватает какой-то общей функциональности,\\ причём расширить суперкласс вы не можете. **Преимущества:** * Отделяет и скрывает от клиента подробности преобразования различных интерфейсов. **Недостатки:** * Усложняет код программы из-за введения дополнительных классов. **Связи с другими паттернами** * Мост проектируют загодя, чтобы развивать большие части приложения отдельно друг от друга. Адаптер применяется постфактум, чтобы заставить несовместимые классы работать вместе. * Адаптер меняет интерфейс существующего объекта. Декоратор улучшает другой объект без изменения его интерфейса. Причём Декоратор поддерживает рекурсивную вложенность, чего не скажешь об Адаптере. * Адаптер предоставляет классу альтернативный интерфейс. Декоратор предоставляет расширенный интерфейс. Заместитель предоставляет тот же интерфейс. * Фасад задаёт новый интерфейс, тогда как Адаптер повторно использует старый. Адаптер оборачивает только один класс, а Фасад оборачивает целую подсистему. Кроме того, Адаптер позволяет двум существующим интерфейсам работать сообща, вместо того, чтобы задать полностью новый. * Мост, Стратегия и Состояние (а также слегка и Адаптер) имеют схожие структуры классов – все они построены на принципе «композиции», то есть делегирования работы другим объектам. Тем не менее, они отличаются тем, что решают разные проблемы. Помните, что паттерны – это не только рецепт построения кода определённым образом, но и описание проблем, которые привели к данному решению. **Adapter.php** outsourceWorker = $outsourceWorker; } public function countSalary(): int { return $this->outsourceWorker->countSalaryByHour(40); } } $nativeDeveloper = new NativeDeveloper(); echo $nativeDeveloper->countSalary(); // 60000 $outsourceDeveloper = new OutsourceDeveloper(); echo $outsourceDeveloper->countSalaryByHour(40); //12000 $outsourceWorkerAdapter = new OutsourceWorkerAdapter($outsourceDeveloper); echo $outsourceWorkerAdapter->countSalary(); // 12000 // ----------- 2 ----------- interface Book { public function turnPage(); public function open(); public function getPage(): int; } class PaperBook implements Book { private int $page; public function open(): void { $this->page = 1; } public function turnPage(): void { $this->page++; } public function getPage(): int { return $this->page; } } interface EBook { public function unlock(); public function pressNext(); /** * возвращает текущую страницу и общее количество страниц, например [10, 100] - страница 10 из 100 * * @return int[] */ public function getPage(): array; } /** * Вот этот адаптер. Обратите внимание, что в нем реализована книга, * таким образом, вам не нужно изменять код клиента, который использует книгу */ class EBookAdapter implements Book { public function __construct(protected EBook $eBook) { } /** * Этот класс выполняет надлежащий перевод с одного интерфейса на другой. */ public function open() { $this->eBook->unlock(); } public function turnPage() { $this->eBook->pressNext(); } /** * обратите внимание на адаптированное поведение здесь: eBook::getPage() вернет два целых числа, но Book * поддерживает только средство получения текущей страницы, поэтому мы адаптируем поведение здесь */ public function getPage(): int { return $this->eBook->getPage()[0]; } } /** * это адаптированный класс. В производственном коде это может быть класс из другого пакета, какой-нибудь код поставщика. * Обратите внимание, что он использует другую схему именования, и реализация делает нечто подобное, но другим способом */ class Kindle implements EBook { private int $page = 1; private int $totalPages = 100; public function pressNext() { $this->page++; } public function unlock() { } /** * возвращает текущую страницу и общее количество страниц, например [10, 100] - страница 10 из 100 * * @return int[] */ public function getPage(): array { return [$this->page, $this->totalPages]; } } $book = new PaperBook(); $book->open(); $book->turnPage(); echo $book->getPage(); // 2 $kindle = new Kindle(); $kindle->unlock(); $kindle->pressNext(); print_r($kindle->getPage()); // [0] => 2 // [1] => 100 $kindle2 = new Kindle(); $book2 = new EBookAdapter($kindle2); $book2->open(); $book2->turnPage(); $book2->turnPage(); echo $book2->getPage(); // 3