Паттерны в разработке приложений. Структурные паттерны
Published 1 февраля 2021 г. 10:52
Сегодня мы продолжаем наше путешествие по паттернам проектирования и на очереди у нас структурные паттерны. Данная группа паттернов весьма полезна, когда вы хотите создать в вашем приложении четкую и легкорасширяемую структуру классов и объектов.
Структурные паттерны - немногочисленное семейство, состоящее из 7 шаблонов:
1. Адаптер (Adapter)
2. Мост (Bridge)
3. Фасад (Facade)
4. Компоновщик (Composite)
5. Декоратор (Decorator)
6. Приспособленец (Flyweight)
7. Заместитель (Proxy)
Адаптер
Начнём с Адаптера :-). Представьте, что вам понадобилось добавить некоторую стороннюю библиотеку в ваше приложение. Она обладает необходимым вам функционалом, самому писать сотни строк кода нет необходимости, но... её интерфейс несовместим с интерфейсом вашего основного класса! Печаль, беда, неужели придётся переписывать старый код только для того, чтобы подключить эту библиотеку (Т_Т).
Возможно, для кого-то это не составляет особого труда и, быть может, даже приносит удовольствие (страшные люди), но большинство предпочитает использовать менее времязатратные решения. Тут как раз приходит на помощь паттерн Адаптер. С его помощью мы можем совместить несовместимое (вспоминаем старые добрые переходники) и заставить классы с различными интерфейсами взаимодействовать друг с другом с помощью промежуточного объекта. Здесь, а также здесь можно найти примеры реализации данного шаблона.
Мост
Для следующего шаблона приведём пример (довольно распространённый) с классом фигур. Допустим, у вас есть некие фигуры и у данных фигур есть цвет. При добавлении новой фигуры нам необходимо будет добавлять ещё один класс для реализации цвета. Так иерархия класса Фигура становится раздутой и мало поддающейся простым изменениям.
Здесь нам поможет паттерн Мост. Используя данный шаблон, мы можем отделить абстракцию от реализации и избежать их крепкой связности. Согласитесь, намного проще вносить изменения по отдельности, чем в непонятный код представляющий из себя смесь строк из вашего представления и абстрактных сущностей. А потом ещё искать причины, почему же ваш код перестал работать. На данном ресурсе вы сможете посмотреть примеры реализации паттерна.
Фасад
Внутреннее взаимодействие отдельных компонентов программы зачастую бывает достаточно сложно устроено и это отнюдь не радует тех, кто вынужден использовать все эти сложные переплетения классов и объектов напрямую. Хочется прикрыть этого программного монстра какой-нибудь ширмой и оставить лишь пару мест для взаимодействия с ним, при этом не уменьшая функциональность программы.
Паттерн Фасад прекрасно справится с данной задачей. С его помощью вы сможете уменьшить количество зависимостей между клиентом и сложной системой. Также он позволяет упростить взаимодействие между сложной системой и клиентом. Вы можете найти примеры использования здесь и здесь.
Компоновщик
Следующий паттерн Компоновщик можно применять, когда структуру вашей программы можно представить в виде дерева. Допустим, у вас есть приложение для интернет-покупок. Коробка может содержать не только продукты, но и другие коробки с продуктами. И для того, чтобы вам посчитать итоговую стоимость заказа, придётся открыть все коробки (0_0). Звучит страшно, да?
Чтобы не тратить на это скучное и нудное занятие строки кода (а главное своё драгоценное время!) можно воспользоваться Компоновщиком. По сути своей он предлагает единый интерфейс для управления различными компонентами программы, которые представляют собой древовидную структуру. Простой пример - каталог файлов и папок. Папки могут содержать другие папки и файлы, с той лишь разницей, что в папку мы можем добавить ещё файлы или папки, а файл является терминальным объектом (листом дерева). Вот ресурс с кодом.
Декоратор
Представьте, что вам заказали простой редактор для фото. Там должны быть рамки, какие-либо фильтры и возможность добавления текста на картинку. Вот сделали вы это приложение, отдали готовую работу заказчику и сидите мирно попиваете чай. А не тут то было :-). Клиент захотел добавить дополнительного функционала приложению: добавление стикеров и эмоджи. Изменять весь код ради добавления парочки функций - сущий Ад. Поэтому здесь можно воспользоваться одним из шаблонов - Декоратором.
Декоратор позволяет динамически добавлять функциональность, не изменяя при этом изначальной структуры. Он поможет избежать проблемы разрастания количества классов из-за наследования, а также позволить добавлять и удалять необходимый функционал программы. Примеры кода и использования: здесь и здесь.
Приспособленец
Настал тот день, когда вы решили попробовать себя в создании невероятных визуальных эффектов (допустим, для видеоигр). На визуализацию вы уделили огромное количество времени, картинка получилась настолько чёткой и живой, что вы совершенно не заметили расхода памяти на эту красоту, пока ваша игра не начала вылетать. Покопавшись, вы наконец обнаружили, что даже ваши 16 Гб видеопамяти не справляются с вашим шедевром. Но это не значит, что вашу игру должна постигнуть участь нажатия кнопки Delete.
На самом деле, для вашей потрясающей детализации вы использовали создание отдельных объектов на каждый листик и пылинку в своей игре :-). Чтобы избежать такого расхода памяти, можно воспользоваться шаблоном Приспособленец. Он позволяет разделять состояния единого объекта, уменьшая расход памяти. То есть мы можем выделить какие-то неизменные части нашего объекта, а изменяемые части использовать в качестве его состояния. Ресурсы с кодом: код1 и код2.
Заместитель
Наш последний гость - паттерн Заместитель (иногда его не переводят и называют также, как в оригинале - Прокси). Он будет полезен, когда обращение к реальным объектам программы будет слишком накладно в плане быстродействия или же мы хотим выполнить некоторые дополнительные действия, прежде чем передать запрос реальному объекту. Строго говоря, мы создаём объект-суррогат, который имеет тот же интерфейс, что и оригинал. Данный объект может кешировать запросы, выполнять защитные функции, создавать объекты по мере их необходимости и т. д. Подробнее с паттерном можно ознакомится здесь и здесь.
Итак, сегодня мы узнали о структурных паттернах и их пользе в процессе разработки ПО. В следующих постах (а их будет 2) мы завершим наше знакомство с паттернами проектирования :-).
Похожие публикации
Паттерны в разработке приложений. Поведенческие паттерны. Часть 2.
Паттерны в разработке приложений. Поведенческие паттерны. Часть 1.