Готовый код на адаптеры в java. Паттерн проектирования Adapter (Адаптер) на PHP. Реализация паттерна Adapter на основе закрытого наследования

В прошлом уроке мы рассмотрели возможность шаблона проектирования Фасад, с помощью которого можно перестроить код крупного проекта.

В этой статье под наш прицел попал шаблон проектирования под названием Адаптер. Его использование целесообразно, если в вашем проекте происходит взаимодействие с сторонними API, или другим классом, который подвержен частым изменениям. Данный шаблон относится к "структурному" типу т.к. с его помощью мы можем мы можем организовать структуру классов по определённому образцу.

Ещё раз хотел бы напомнить, что шаблоны проектирования ничем не отличаются от обычных классов. С их помощью мы можем лучшим способом структурировать наши классы, управлять их поведением.

Задача

В приведённом примере мы используем класс Twitter для упрощения процедуры публикации сообщения. Далее мы создаём объект для обращения к Twitter API и публикации сообщения. Представьте, что данный код используется в нескольких местах. Обратите внимание, что для публикации сообщения мы используем метод $twitter->send("Posting on Twitter");

Некоторое время назад, Twitter изменили название метода API для публикации сообщения. Те, кто пользовался предыдущей версией явно увидят сложившуюся проблему. Нам необходимо поменять все названия методов для отправки твитта. Представьте сколько кода нам нужно поменять и сколько на это потребуется времени. Что если смена названия произойдёт ещё раз?

Решение

В качестве решения можем применить шаблон проектирования Адаптер.

Адаптер — структурный шаблон проектирования, предназначенный для организации использования функций объекта, недоступного для модификации, через специально созданный интерфейс.

Таким образом, в первую очередь, нам необходимо создать интерфейс. Изменение кода сторонней библиотеки не имеет никакого смысла, т.к. её содержание может в любой момент измениться.

Давайте рассмотрим код, написанный на основе шаблона проектирования Адаптер:

// Имплементация класса Twitter class Twitter { public function __construct() { // Your Code here // } public function send($msg) { // Posting to Twitter // echo $msg; } } // Простой интерфейс для каждого адаптера, который будет создан interface socialAdapter { public function send($msg); } class twitterAdapter implements socialAdapter { private $twitter; public function __construct(Twitter $twitter) { $this->twitter = $twitter; } public function send($msg) { $this->twitter->send($msg); } }

Изучив код вы поймёте, что мы не тронули исходный класс Twitter. Вместо этого мы создали интерфейс нашего социального адаптера для класса Twitter.

Далее вместо создания объекта типа Twitter, мы создали объект его адаптера. В качестве параметра передаём объект основного класса Twitter, для того, чтобы наш адаптер имел доступ к объекту основного класса.

Теперь давайте определим как использовать методы исходного класса:

// клиентский код $twitter = new twitterAdapter(new Twitter()); $twitter->send("Posting to Twitter");

Теперь представьте, что Twitter изменил название метода с send на sendTweet. В этом случае, нам нужно изменить только twitterAdapter. Взгляните на изменённый код адаптера.

Class twitterAdapter implements socialAdapter { private $twitter; public function __construct(Twitter $twitter) { $this->twitter = $twitter; } public function send($msg) { $this->twitter->sendTweet($msg); } }

Только одно изменение и мы снова в теме.

Добавление нового адаптера

Давайте рассмотрим как можно использовать шаблон проектирования Адаптер в других случаях. Теперь очень просто добавить новый класс на основе существующего адаптера. Допустим Facebook API позволяет обновить статус.

Вместо того чтобы напрямую использовать класс Facebook, создадим новый адаптер.

Class Facebook { public function __construct() { // Ваш код // } public function updateStatus($msg) { // Пост на Facebook // echo $msg; } } // Адаптер Facebook class facebookAdapter implements socialAdapter { private $facebook; public function __construct(Facebook $facebook) { $this->facebook = $facebook; } public function send($msg) { $this->facebook->updateStatus($msg); } } // клиентский код $facebook = new facebookAdapter(new Facebook()); $facebook->send("Posting to Facebook");

Как видите, принцип тот же. Вы определяете класс оболочку, в который передаёте оригинальный объект класса. При изменении API, вам нужно сменить код только в одном месте.

Заключение

Крупные приложения несомненно включат в себя работу с сторонними API, так что использование шаблона проектирования Адаптер целесообразно, если вы хотите избежать рассмотренной нами проблемы.

Я сделал всё зависящее от меня, чтобы продемонстрировать элементарный и одновременно полезный пример использования шаблона проектирования Адаптер.

    Основная статья: Адаптер (шаблон проектирования) Пример реализации шаблона на C# using System; namespace Adapter { class MainApp { static void Main() { … Википедия

    У этого термина существуют и другие значения, см. Паттерн. В разработке программного обеспечения, шаблон проектирования или паттерн (англ. design pattern) повторимая архитектурная конструкция, представляющая собой решение проблемы… … Википедия

    Шаблон проектирования Интерфейс Interface Описан в Design Patterns Нет В информатике, шаблон интерфейса не является особым шаблоном среди шаблонов проектирования. Он является общим методом для структурирования компьютерных программ для того … Википедия

    Шаблон Proxy (Заместитель) Шаблон проектирования. Предоставляет объект, контролирующий доступ, перехватывая все вызовы к нему. Содержание 1 Цель 1.1 Проблема 1.2 Решение 2 Плюсы 3 … Википедия

    Шаблон проектирования Хранитель Memento Тип: поведенческий Описан в Design Patterns Да Хранитель (также известный как Memento, Token, Лексема) поведенческий шаблон проектирования. Позволяет, не нарушая инкапсуляцию, зафикс … Википедия

    Шаблон проектирования Итератор Iterator Тип: поведенческий Описан в Design Patterns Да Шаблон Iterator (также известный как Cursor) Шаблон проектирования, относится к паттернам поведения. Представляет собой объект, позволяющий получить … Википедия

    Шаблон проектирования Интерпретатор Interpreter Тип: поведенческий Назначение: решает часто встречающуюся, подверженную изменениям задачу Описан в Design Patterns Да Шаблон Интерпретатор (англ. … Википедия

    Шаблон проектирования Компоновщик Composite Тип: структурный Описан в Design Patterns Да Компоновщик (англ. Composite pattern) шаблон проектирования, относится к структурным паттернам, объединяет объек … Википедия

    Шаблон проектирования Состояние State Тип: поведенческий Описан в Design Patterns Да Состояние (англ. State) шаблон проектирования. Используется в тех случаях, когда во время выполнения программы объект … Википедия

Назначение

Адаптер (англ. Adapter или англ. Wrapper -Обёртка) - структурный шаблон проектирования, предназначенный для организации использования функций объекта, недоступного для модификации, через специально созданный интерфейс.

Задача

Система поддерживает требуемые данные и поведение, но имеет неподходящий интерфейс.

Способ решения

Адаптер предусматривает создание класса-оболочки с требуемым интерфейсом.

Участники

Класс Adapter приводит интерфейс класса Adaptee в соответствие с интерфейсом класса Target (наследником которого является Adapter). Это позволяет объекту Client использовать объект Adaptee (посредством адаптера Adapter) так, словно он является экземпляром класса Target .

Таким образом Client обращается к интерфейсу Target , реализованному в наследнике Adapter, который перенаправляет обращение к Adaptee.

UML-диаграмма классов паттерна Adapter

Следствия

Шаблон Адаптер позволяет включать уже существующие объекты в новые объектные структуры, независимо от различий в их интерфейсах.

Описание

Пусть класс, интерфейс которого нужно адаптировать к нужному виду, имеет имя Adaptee. Для решения задачи преобразования его интерфейса паттерн Adapter вводит следующую иерархию классов:

    Виртуальный базовый класс Target. Здесь объявляется пользовательский интерфейс подходящего вида. Только этот интерфейс доступен для пользователя.

    Производный класс Adapter, реализующий интерфейс Target. В этом классе также имеется указатель или ссылка на экземпляр Adaptee. Паттерн Adapter использует этот указатель для перенаправления клиентских вызовов в Adaptee. Так как интерфейсы Adaptee и Target несовместимы между собой, то эти вызовы обычно требуют преобразования.

Паттерн Adapter, представляющий собой программную обертку над существующими классами, преобразует их интерфейсы к виду, пригодному для последующего использования.

Рассмотрим простой пример, когда следует применять паттерн Adapter. Пусть мы разрабатываем систему климат-контроля, предназначенной для автоматического поддержания температуры окружающего пространства в заданных пределах. Важным компонентом такой системы является температурный датчик, с помощью которого измеряют температуру окружающей среды для последующего анализа. Для этого датчика уже имеется готовое программное обеспечение от сторонних разработчиков, представляющее собой некоторый класс с соответствующим интерфейсом. Однако использовать этот класс непосредственно не удастся, так как показания датчика снимаются в градусах Фаренгейта. Нужен адаптер, преобразующий температуру в шкалу Цельсия.

Реализация

namespace Adapter

static void Main()

// Create adapter and place a request

Target target = new Adapter();

target.Request();

// Wait for user

public virtual void Request()

Console.WriteLine("Called Target Request()");

class Adapter: Target

private Adaptee adaptee = new Adaptee();

public override void Request()

// Possibly do some other work

// and then call SpecificRequest

adaptee.SpecificRequest();

public void SpecificRequest()

Console.WriteLine("Called SpecificRequest()");

Результаты применения паттерна Adapter

Достоинства паттерна Adapter

    Паттерн Adapter позволяет повторно использовать уже имеющийся код, адаптируя его несовместимый интерфейс к виду, пригодному для использования.

Недостатки паттерна Adapter

    Задача преобразования интерфейсов может оказаться непростой в случае, если клиентские вызовы и (или) передаваемые параметры не имеют функционального соответствия в адаптируемом объекте.

Перед прочтением ознакомьтесь с , в котором описаны принятые соглашения и понятия. Данная статья дополняется с некоторой периодичностью, так что если вы ее читали ранее, не факт что данные не изменились.

Adapter (Адаптер) относиться к классу структурных паттернов. Он используется для преобразования одного интерфейса в другой, необходимый клиенту. Адаптер обеспечивает совместимость несовместимых интерфейсов, реализуя прослойку.

Принцип работы

Адаптер наследует открытым способом целевой интерфейс (назовем его Target ), и закрытым способом адаптируемый интерфейс (Adaptee ). В реализации методов целевого интерфейса происходит перенаправление (делегирование) запросов классу с адаптируемым интерфейсом

Пример

// Целевой интерфейс, клиент умеет работать только с ним interface iTarget { public function query(); } // Адаптируемый интерфейс. Клиент с ним не умеет работать, но очень хочет interface iAdaptee { public function request(); } // Класс, реализующий адаптирумым интерфейс class Adaptee implements iAdaptee { public function request() { return __CLASS__ . "::" . __METHOD__; } } class Adapter implements iTarget { protected $adaptee = null; public function __construct() { $this -> adaptee = new Adaptee(); } public function query() { return $this -> adaptee -> request(); } } $Target = new Adapter(); print $Target -> query(); // "Adaptee::request"

Заключение

Адаптер может адаптировать в единый сразу несколько интерфейсов, такой паттерн называют адаптер объектов Использование этого паттерна оправдано в нескольких случаях. Если вы хотите использовать существующий класс с иным интерфейсом. Если адаптируемый интерфейс собираетесь использовать в нескольких местах, и не имеете возможности везде привести к единому виду, тогда использование сменных адаптеров может оказаться хорошей идеей.

Всем привет! Сегодня мы поговорим о шаблоне проектирования Адаптер(Pattern Adapter) . Как понятно из названия, служит он для того, чтобы что-то адаптировать , но вот что? А на этот вопрос вам ответит эта статья.

Описание шаблона проектирования Адаптер

Давайте немного отойдем от программирования и посмотрим на адаптеры в реальной жизни. К примеру, вы купили какую-то технику(например, компьютер) за границей. Приехав с ней домой, вы обнаружили, что вилка другого стандарта и в нашу, российскую розетку, не подходит. Что же делать? Правильно! Нужно пойти в магазин и купить переходник , используя который вы сможет подключить ваш компьютер в сеть. Так вот, этот переходник и есть адаптер . В него мы вставляем иностранную вилку, а сам адаптер включаем в сеть и все прекрасно работает. Т.е. он служит просто прослойкой между нашей розеткой и иностранной вилкой.

Итак, думаю, что вы разобрались, что такое адаптер в жизни. В программировании - это то же самое.

Пример реализации адаптера на PHP

interface iMain {
public function send();
}

Interface iAdaptee {
public function inquiry();
}

Class Adaptee implements iAdaptee {
public function inquiry() {
return __CLASS__."::".__METHOD__;
}
}

Class Adapter implements iMain {
protected $adaptee = null;

Public function __construct() {
$this->adaptee = new Adaptee();
}

Public function send() {
return $this->adaptee->inquiry();
}
}

$goal = new Adapter();
echo $goal->send(); // "Adaptee::inquiry"
?>

Итак, вот наш код. Давайте разбираться. У нас есть интерфейс iMain , клиентский код умеет работать с ним. Дальше у нас есть интерфейс iAdaptee , с которым клиентский код работать не умеет, но нам необходимо как-то с ним взаимодействовать. Потом у нас есть класс Adaptee iAdaptee и внутри у него есть метод с именем inquiry , который просто возвращает строку вида CLASS::METHOD . Вот мы подошли к классу Adapter , который наследует интерфейс iMain . Внутри него мы создаем защищенное свойство adaptee , равное null . Дальше в конструкторе мы создаем объект класса Adaptee и записываем его в наше защищенное свойство. В методе send мы возвращаем вызов метода inquiry .

Вот и все. Теперь создаем объект нашего адаптера и вызываем метод send .

Т.е. вся суть в том, что мы можем работать с одним интерфейсом, но не можем с другим и, чтобы как-то взаимодействовать с этим недоступным нам интерфейсом, мы и создаем адаптер , прослойку, через которую и реализуем нашу задачу.

Заключение

Сейчас вам может показаться, что все очень сложно и трудно, но это не так. Думаю, смысл адаптера вы поняли, а теперь вам нужно больше практики. Просмотрите еще раз код, который дан в этой статье, и попытайтесь его осмыслить. Строчка за строчку просматривайте и проговаривайте его, как будто вы интерпретатор php . Также, советую просмотреть код какого-нибудь фреймворка, ведь там этот шаблон используется довольно часто.

На этом я заканчиваю эту немаленькую статью, спасибо за внимание!