О структурных шаблонах проектирования простым языком

Posted by

Рассказывает Камран Ахмед

Шаблоны проектирования — это руководства по решению повторяющихся проблем. Это не классы, пакеты или библиотеки, которые можно было бы подключить к вашему приложению и сидеть в ожидании чуда. Они скорее являются методиками решения определенных проблем в определенных ситуациях.

Википедия описывает их следующим образом:

Будьте осторожны

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

Также заметьте, что примеры ниже написаны на PHP 7. Но это не должно вас останавливать, ведь принципы остаются такими же.

Типы шаблонов

Шаблоны бывают следующих трех видов:

— Порождающие.
— Структурные — о них мы рассказываем в этой статье.
— Поведенческие.

Простыми словами: Структурные шаблоны в основном связаны с композицией объектов, другими словами, с тем, как сущности могут использовать друг друга. Ещё одним объяснением было бы то, что они помогают ответить на вопрос «Как создать программный компонент?».

Википедия гласит:

Список структурных шаблонов проектирования:

адаптер (Adapter);
мост (Bridge);
компоновщик (Composite);
декоратор (Decorator);
фасад (Facade);
приспособленец (Flyweight);
заместитель (Proxy).

Адаптер (Adapter)

Википедия гласит:

Пример из жизни: Представим, что у вас на карте памяти есть какие-то изображения и вам надо перенести их на ваш компьютер. Чтобы это сделать, вам нужен какой-то адаптер, который совместим с портами вашего компьютера. В этом случае карт-ридер — это адаптер. Другим примером будет блок питания. Вилку с тремя ножками нельзя вставить в розетку с двумя отверстиями. Для того, чтобы она подошла, надо использовать адаптер. Ещё одним примером будет переводчик, переводящий слова одного человека для другого.

Простыми словами: Шаблон позволяет обернуть несовместимые объекты в адаптер, чтобы сделать их совместимыми с другим классом.

Обратимся к коду. Представим игру, в которой охотник охотится на львов.

Изначально у нас есть интерфейс Lion, который реализует всех львов:

И Hunter охотится на любую реализацию интерфейса Lion:

Теперь представим, что нам надо добавить WildDog в нашу игру, на которую наш Hunter также мог бы охотиться. Но мы не можем сделать это напрямую, потому что у WildDog другой интерфейс. Чтобы сделать её совместимой с нашим Hunter, нам надо создать адаптер:

Способ применения:

Примеры на Java и Python.

Мост (Bridge)

Википедия гласит:

Пример из жизни: Представим, что у вас есть сайт с разными страницами, и вам надо разрешить пользователям менять их тему. Что вы будете делать? Создавать множественные копии каждой страницы для каждой темы или просто отдельную тему, которую пользователь сможет выбрать сам? Шаблон мост позволяет вам сделать второе.

Простыми словами: Шаблон мост — это предпочтение композиции над наследованием. Детали реализации передаются из одной иерархии в другой объект с отдельной иерархией.

Обратимся к примеру в коде. Возьмем пример с нашими страницами. У нас есть иерархия WebPage:

И отдельная иерархия Theme:

Применение в коде:

Примеры на Java и Python.

Компоновщик (Composite)

Википедия гласит:

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

Простыми словами: Шаблон компоновщик позволяет клиентам работать с индивидуальными объектами в едином стиле.

Обратимся к коду. Возьмем наш пример с рабочими. У нас есть Employee разных типов:

Теперь у нас есть TaskManager:

Способ применения:

Примеры на Java и Python.

Декоратор (Decorator)

Википедия гласит:

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

Простыми словами: Шаблон декоратор позволяет вам динамически изменять поведение объекта во время работы, оборачивая их в объект класса декоратора.

Перейдем к коду. Возьмем пример с кофе. Изначально у нас есть простой Coffee и реализующий его интерфейс:

Мы хотим сделать код расширяемым, чтобы при необходимости можно было изменять его. Давайте сделаем некоторые дополнения (декораторы):

А теперь приготовим Coffee:

Примеры на Java и Python.

Фасад (Facade)

Википедия гласит:

Пример из жизни: Как вы включаете компьютер? Нажимаю на кнопку включения, скажете вы. Это то, во что вы верите, потому что вы используете простой интерфейс, который компьютер предоставляет для доступа снаружи. Внутри же должно произойти гораздо больше вещей. Этот простой интерфейс для сложной подсистемы называется фасадом.

Простыми словами: Шаблон фасад предоставляет упрощенный интерфейс для сложной системы.

Перейдем к примерам в коде. Возьмем пример с компьютером. Изначально у нас есть класс Computer:

Затем у нас есть фасад:

Пример использования:

Примеры на Java и Python.

Приспособленец (Flyweight)

Википедия гласит:

Пример из жизни: Вы когда-нибудь заказывали чай в уличном ларьке? Там зачастуют готовят не одну чашку, которую вы заказали, а гораздо большую емкость. Это делается для того, чтобы экономить ресурсы (газ/электричество). Газ/электричество в этом примере и являются приспособленцами, ресурсы которых делятся (sharing).

Простыми словами: Приспособленец используется для минимизации использования памяти или вычислительной стоимости путем разделения ресурсов с наибольшим количеством похожих объектов.

Перейдем к примерам в коде. Возьмем наш пример с чаем. Изначально у нас есть различные виды Tea и TeaMaker:

Теперь у нас есть TeaShop, который принимает заказы и выполняет их:

Пример использования:

Примеры на Java и Python.

Заместитель (Proxy)

Википедия гласит:

Пример из жизни: Вы когда-нибудь использовали карту доступа, чтобы пройти через дверь? Есть несколько способов открыть дверь: например, она может быть открыта при помощи карты доступа или нажатия кнопки, которая обходит защиту. Основная функциональность двери — это открытие, но заместитель, добавленный поверх этого, добавляет функциональность. Но лучше я объясню это на примере кода чуть ниже.

Простыми словами: Используя шаблон заместитель, класс отображает функциональность другого класса.

Перейдем к коду. Возьмем наш пример с безопасностью. Сначала у нас есть интерфейс Door и его реализация:

Затем у нас есть заместитель Security для защиты любых наших дверей:

Пример использования:

Другим примером будет реализация маппинга данных. Например, недавно я создал ODM (Object Data Mapper) для MongoDB, используя этот шаблон, где я написал заместитель вокруг классов mongo и использовал магический метод __call(). Все вызовы методов были замещены оригинальным классом mongo, и полученный результат возвращался без изменений, но в случае find или findOne данные сопоставлялись необходимому классу, и возвращались в объект вместо Cursor.

Примеры на Java и Python.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *