В прошлой статье я уже рассказал о таких шаблонах проектирования как декоратор, мост, фабрика и абстрактная фабрика, которые часто позволяют программисту уменьшить сложность конкретного класса/функции. Теперь же пришло время рассмотреть настолько же часто используемые и полезные шаблоны определяющие взаимодействие между частями системы, а также внешними API.
Напомним несколько важных моментов
Все примеры кода в статье выполнены на php7.3 и протестированы на linux (debian). Сами примеры могут получиться немного больше, чем могли бы быть, но это связано с желанием продемонстрировать их работу на каком-то реальном примере, а не "давайте унаследуем собачку и кошечку от класса животных", что обычно не даёт ни малейшего понимания какие трудности могут возникать при применении шаблона.
Наблюдатель
Данный шаблон реализует самую простейшую систему событий, когда один объект подписывается на события другого, по возникновению которых второй объект будет вызывать соответствующий метод первого, оповещая его об этом событии. Разумеется все наблюдатели обязуются реализовать соответствующий интерфейс.
Допустим у нас есть пользователь и нам надо в разных источниках логировать его действия или обрабатывать в других частях системы. Тогда делаем объект пользователя наблюдаемым и цепляем к нему всех нужных наблюдателей (я зацепил к нему в примере 2 одинаковых наблюдателя для простоты и наглядности) :
Если запустить код, то видно, что на изменение логина среагируют оба логера, а на изменение имени только один.
Издатель-подписчик
Этот шаблон очень похож на "Наблюдатель", но является его более сложной доработанной версией. Отличие от наблюдателя тут в том, что в систему добавляется третий управляющий событиями объект, что позволяет полностью отвязать друг от друга наблюдателей и наблюдаемые объекты и сделать систему более гибкой. То есть подписчики (наблюдатели) подписываются на события у некоторого посредника, а издатели (наблюдаемые) вызывают соответствующий метод посредника, который сам уже занимается передачей информации о событиях.
Например это может быть полезно при сложной системе событий или если надо отслеживать все события отправленных объектами одного класса:
Как видно, код стал немного сложнее, но зато теперь мы можем гибко управлять события, отслеживая конкретное событие по типу, все события объекта, конкретное событие любого объекта или вообще любое событие, что и продемонстрировано в примере (событие изменения логина вызывает все три логера, событие изменения имени - 2 логера, а событие на другом объекте - 1 логер. Также важно заметить, что издатель ничего о подписчике не знает, а потому на его события подписаться может кто угодно и код издателя менять не придётся.
Посредник
По сути это двухсторонний декоратор, задача которого не расширить/модифицировать какой-то объект, а подружить 2 объекта с несовместимыми интерфейсами. Посредник - это как переходник на розетку и вилку, которые друг с другом несовместимы.
Например представим, что у нас есть класс часов, который принимает и отдаёт данные через сокет, но мы хотим вместо сокета подсунуть ему консольный обработчик команд
Как видно из кода, интерфейс консоли сильно отличается от интерфейса сокета, а интерфейс отработки команд сильно отличается от интерфейса часов. Таким образом подружить не переписывая их было невозможно. Однако написав посредника, который с одной стороны будет вести себя как сокет, а с другой как контроллер, мы смогли через него связать консольный обработчик команд и объект часов.
Фасад
Один из самых простых и полезных шаблонов. Назначение шаблона - упростить взаимодействие с частью системы или внешним API, скрыв за ним ненужные детали.
Представим у нас есть SDK API яндекс кассы, paypal или другой платёжной системы с кучей методов и нюансов. Можно, конечно, просто кинуть его в систему и заставить всех с этим всем зоопарком методов и вызовов разбираться. Но если из всего арсенала нам нужна только функция покупки и её отмены, то очень логичным является создание объекта, реализующего два простых метода buy и cancelBuy (ну и возможно connect, validateSignature и ещё несколько служебных), что сильно облегчит работу в будущем, когда не придётся перекапывать километры документации и сотни методов и процедур. Полагаю эта идея достаточно проста и потому в демонстрации кодом не нуждается.
В следующих статьях
Это далеко не всё! В будущем рассмотрим шаблоны общего доступа к компонентам системы и шаблоны переопределения алгоритмов: одиночка, локатор служб, цепочка обязанностей, заместитель, стратегия, шаблонный метод
Подписывайтесь, если Вам понравилась статья, ставьте лайки и комментируйте