Разработка программного обеспечения совершенствуется каждый день благодаря новым концепциям, методологиям и высококачественным библиотекам и инфраструктурам. Но даже со всеми этими улучшениями мы не можем предотвратить изменения в разработке программного обеспечения. Вы можете подумать, что ваша система разработана с учетом всех ее требований, но всегда будет запрос на изменение, который разрушит ваш идеальный дизайн. Мы должны быть готовы ко всем возможным изменениям как разработчики.
Шаблон адаптера — это шаблон проектирования, который обычно используется для управления изменениями в разработке. В этой статье мы рассмотрим использование и преимущества шаблонов, используемых в реальных приложениях.
Что такое шаблон адаптера?
Шаблон проектирования адаптера упрощает задачи, адаптируясь к изменениям существующих функциональных возможностей, а также создавая новые функциональные возможности. Короче говоря, мы можем определить адаптер как интерфейс, который помогает интегрировать несовместимые компоненты.
Предположим, у нас есть мобильный телефон, который используется для доступа к учетной записи электронной почты для отправки писем. Приложение для телефона и электронной почты действует как отдельные компоненты, которые подключаются через Интернет.
Теперь предположим, что мы путешествуем в место, где подключение к Интернету недоступно для телефона. Как нам получить доступ к электронной почте в этой ситуации? Нам нужен адаптер, который соединяет наш мобильный телефон с приложением электронной почты. Давайте посмотрим на функции, ожидаемые от такого адаптера:
- Включите интернет-соединение между мобильным телефоном и почтовым приложением.
- Доступ к API приложения электронной почты для отправки электронной почты.
Учитывая требования, мы можем выбрать IFTTT в качестве адаптера. IFTTT — это сервис, который поддерживает автоматизацию задач с помощью популярных API. Таким образом, мы можем использовать IFTTT в качестве адаптера, как показано на рисунке ниже.
В этом решении мы отправляем SMS-сообщение в службу IFTTT, содержащее текст сообщения. Для отправки SMS на международный номер не требуется подключение к Интернету. Затем служба IFTTT получает содержимое сообщения и инициализирует рецепт (рецепты должны быть предварительно настроены), чтобы отправить электронное письмо с помощью API почтового приложения.
IFTTT имеет доступ к API электронной почты, а также к интернет-соединению с приложением электронной почты, выполняя оба требования, ожидаемые от адаптера. IFTTT выступает в роли адаптера для интеграции нашего приложения для телефона и электронной почты, которое находилось в несовместимом состоянии из-за недоступности Интернета.
Я думаю, что к настоящему времени у вас должно быть четкое понимание функциональности шаблона адаптера в реальном мире. Прежде чем мы перейдем к реализации, давайте взглянем на определение шаблона, данное в Википедии :
В компьютерном программировании шаблон адаптера — это шаблон проектирования, который переводит один интерфейс для класса в совместимый интерфейс. Адаптер позволяет классам работать вместе, что обычно невозможно из-за несовместимых интерфейсов, предоставляя его интерфейс клиентам при использовании исходного интерфейса. ,
Понимание реализации шаблона адаптера
Было бы идеально использовать практический сценарий для понимания процесса и компонентов шаблона адаптера, поэтому предположим, что у нас есть общий интерфейс для подписок по электронной почте для нашего веб-сайта. Следующий код содержит реализацию интерфейса подписки на электронную почту.
<?php
interface EmailSubscribe
{
public function subscribe($email);
public function unsubscribe($email);
public function sendUpdates();
}
Разработчики и поставщики услуг электронной почты могут реализовать этот интерфейс для предоставления классов подписки электронной почты для каждого из поставщиков электронной почты, таких как Feedburner, Mailchimp и т. Д. Следующий код содержит пример реализации для одной службы и инициализации метода sendUpdates()
<?php
class FeedburnerEmail implements EmailSubscribe
{
public function subscribe($email) { }
public function unsubscribe($email) { }
public function sendUpdates() {
// Get Available Subscribers
// Get Website Updates
// Send Emails
}
}
$feedburner_email = new FeedburnerEmail();
$feedburner_email->sendUpdates();
Теперь предположим, что Feedburner решает изменить свою библиотеку на последнюю версию.
<?php
class FeedburnerEmailVersion2
{
public function subscribe($email) { }
public function unsubscribe($email) { }
public function getSubscribers() {
// Return Subscribers
}
public function sendEmails($subscribers) {
// Get Website Updates
// Send Emails
echo "emails sent today";
}
}
$feedburner_email = new FeedburnerEmailVersion2();
$subscribers = $feedburner_email->getSubscribers();
$feedburner_email->sendEmails($subscribers);
Согласно предыдущему коду, добавляются новые методы, а существующая функциональность изменяется в новой версии библиотеки. Код инициализации изменился, и последняя версия Feedburner стала несовместимой с интерфейсом EmailSubscribe
Мы не можем реализовать общий интерфейс, и поэтому нам нужен адаптер, чтобы сделать библиотеку совместимой с исходным интерфейсом, чтобы сохранить согласованность в нашем коде. Поскольку текущая версия не реализует интерфейс, у нас нет другого выбора, кроме как создать адаптер на основе интерфейса.
<?php
class FeedburnerAdapter implements EmailSubscribe
{
public function subscribe($email) { }
public function unsubscribe($email) { }
public function sendUpdates() {
$feedburner = new FeedburnerEmailVersion2();
$subscribers = $feedburner->getSubscribers();
$feedburner->sendEmails($subscribers);
}
}
$feedburner_email = new FeedburnerAdapter();
$feedburner_email->sendUpdates();
Адаптер FeedburnerAdapter
sendUpdates()
Теперь наше приложение и библиотека Feedburner взаимодействуют через стандартный интерфейс FeedburnerAdapter
Наше приложение не знает, что реализация изменилась, и вместо исходного библиотечного класса работает адаптер. Разработчики могут вызывать стандартный набор методов, не внося никаких изменений в свой исходный код.
Теперь пришло время понять теоретические аспекты паттерна Adapter, используя его диаграмму классов.
Обычно в нашем приложении есть Client
Target
Adaptee
Adaptee
Target
В ситуациях, когда Client
Adaptee
Adapter
Target
Adaptee
Диаграмма выше содержит оригинальный дизайн шаблона Adapter для использования в лучших сценариях. Интерфейсы не используются широко в проектах PHP, но это не означает, что вы не можете использовать шаблон адаптера. Пока какой-то компонент объединяет несовместимые интерфейсы, его можно считать адаптером.
В моей последней статье об Opauth мы обсуждали использование класса стратегии в библиотеке Opauth. Он также действует как адаптер, даже если он не реализует никаких интерфейсов. Адаптер стратегии сделал открытые библиотеки аутентификации совместимыми с базовой библиотекой Opauth.
Кто разрабатывает класс адаптера?
Когда нам нужен адаптер, мы можем создать его как разработчика или попросить поставщика предоставить адаптер. Это зависит от ситуации и типа проекта, над которым мы работаем. Если мы разрабатываем приложения с использованием распространенных сторонних библиотек, мы будем нести ответственность за создание адаптеров, соответствующих требованиям. С другой стороны, мы могли бы разрабатывать крупномасштабное приложение и ожидать, что производители разработают библиотеки специально для нашего приложения. В таких случаях, если поставщики изменяют свою библиотеку, они также должны предоставить Адаптер.
Шаблон адаптера — неправильный путь
Многие опытные разработчики считают, что шаблон Adapter используется для исправления плохо спроектированных систем. В зависимости от ситуации нам, возможно, придется согласиться с этим. Но давайте рассмотрим слегка измененную версию примера подписки по электронной почте, который мы обсуждали ранее.
Предположим, что две команды были назначены для разработки классов Feedburner и Mailchimp по отдельности на основе исходного интерфейса, который мы использовали ранее.
<?php
class FeedburnerEmail implements EmailSubscribe
{
public function subscribe($email) { }
public function unsubscribe($email) { }
public function getSubscribers() {
// Returns list of subscribers
}
public function sendUpdates() {
$this->getSubscribers();
// Get Website Updates
// Send Emails
}
}
<?php
class MailchimpEmail implements EmailSubscribe
{
public $subscribers;
public function subscribe($email) { }
public function unsubscribe($email) { }
public function getSubscribers() {
$this->subscribers = "List of subscribers";
}
public function sendUpdates() {
$subscribers = $this->subscribers;
// Get Website Updates
// Send Emails
}
}
Хотя оба класса совместимы с целевым интерфейсом, между клиентом и этими двумя классами существует несовместимость. Рассмотрим код инициализации, чтобы лучше это понять:
<?php
$email = FeedburnerEmail();
$email->sendUpdates();
$email = MailchimpEmail();
$email->getSubscribers();
$email->sendUpdates();
Код из Team 2 не совпадает с кодом инициализации клиента и, следовательно, становится несовместимым. Нам нужен адаптер, чтобы исправить проблему для класса Mailchimp. Это считается неправильным использованием шаблона адаптера, так как мы могли бы спланировать интерфейс должным образом, чтобы избежать таких проблем несовместимости.
Шаблон адаптера — правильный путь
Адаптеры в основном используются в ситуациях, когда мы работаем со сторонними библиотеками или создаем новую функциональность, которая значительно отличается от исходных требований. Итак, рассмотрим следующий сценарий эффективного использования адаптеров.
Электронная подписка отлично работает на нашем сайте. В связи с успехом подписок, руководство планирует внедрить подписки Twitter для сайта. В настоящее время, когда пользователь подписывается по электронной почте, он или она получает уведомления по электронной почте об обновлениях содержимого веб-сайта. С новым требованием, в основном пользователь подписывается, аутентифицируя свою учетную запись Twitter для нашего сайта. Каждый раз, когда сайт обновляется, в его твиттере об обновлении будут создаваться новые твиты.
Следующий код содержит библиотеку Twitter для этой реализации.
<?php
class TwitterService
{
public function authenticate($username) {}
public function deauthenticate($username) {}
public function tweet($message,$user) {
// Update wall with new tweet
}
public function getUpdates() {
// Return Updates
}
public function getFollowers() {
// Return followers
}
}
Мы не можем сделать TwitterService
Но мы можем видеть, что логика класса похожа на EmailSubscription
Следовательно, в этой ситуации мы можем эффективно использовать класс адаптера, чтобы сделать TwitterService
Давайте посмотрим на реализацию класса TwitterAdapter
<?php
class TwitterAdapter implements EmailSubscribe
{
public function subscribe($username) { }
public function unsubscribe($username) { }
public function sendUpdates() {
$tw_service = new TwitterService();
$updates = $tw_service->getUpdates();
$subscribers = $tw_service->getFollowers();
$tw_service->tweet($updates,$subscribers);
}
}
$twitter_subscribe = new TwitterAdapter();
$twitter_subscribe->sendUpdates();
Класс TwitterAdapter
Внутренне он создает объект TwitterService
sendUpdates()
Код инициализации кажется похожим на предыдущий код. Следовательно, клиентский класс не знает, что сервис Twitter отправляет твит вместо обновлений по электронной почте. Клиентский класс продолжает вызывать метод sendUpdate()
Резюме
В этой статье мы рассматривали шаблон адаптера и пытались понять его эффективное использование на нескольких практических примерах. Мы узнали, что существует и хорошее, и плохое использование шаблона адаптера, и теперь вам решать, когда использовать адаптеры.
Сообщите мне о практических сценариях, с которыми вы столкнулись при разработке приложений, и о том, как вы предлагали решение с помощью адаптеров, в комментариях ниже.
Изображение через Fotolia