JavaRush /Курсы /JSP & Servlets /Структурные паттерны

Структурные паттерны

JSP & Servlets
16 уровень , 1 лекция
Открыта

2.1 Adapter

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

Официальное определение немного сложновато воспринимается, но если описать его своими словами, то адаптер — это паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе.

Adapter pattern

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

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

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

Сильные стороны:

  • Переход на использование других внешних классов не требует переделки самой системы, достаточно реализовать еще один класс Adapter.
  • Независимость от реализации внешних классов (классов из библиотек, чей код мы не можем поменять). Твоя программа становится независимой от интерфейса внешних классов.

2.2 Decorator

Декоратор (Decorator) — структурный шаблон проектирования, предназначенный для динамического подключения дополнительного поведения к объекту. Шаблон Декоратор предоставляет хорошую и гибкую альтернативу практике создания подклассов с целью расширения функциональности.

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

Используется для динамического подключения к объекту дополнительных обязательств.

Многие из вас спросят: как можно динамически (во время работы программы) добавить объекту новое поведение? Объект можно собрать из кусочков, то есть маленьких объектов. Помнишь цепочки фильтров в сервлетах? Или Stream API, когда ты писал запрос с использованием filter(), map(), list()?


IntStream.of(50, 60, 70, 80, 90).filter(x -> x < 90).map(x -> x + 10).limit(3).forEach(System.out::print);

Сильные стороны паттерна Decorator:

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

2.3 Proxy

Заместитель (Proxy) — структурный шаблон проектирования, предоставляющий объект, который контролирует доступ к другому объекту, перехватывая и пропуская через себя все его вызовы.

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

Паттерн Proxy предоставляет объект-заменитель вместо настоящего объекта. Этот объект контролирует доступ к оригинальному объекту. Используется очень часто.

Помнишь, как мы использовали фреймворк Mockito и перехватывали обращение к реальному объекту с помощью метода Mockito.spy() или аннотации @Spy? Именно тогда и создавался специальный Proxy-объект, через который проходили все вызовы к оригинальному объекту.

И мы тогда с помощью добавления объекту правил могли этими вызовами управлять. Именно так – оригинальный объект не меняется, а работа с ним становится значительно гибче. Особенно полезно бывает, когда не мы из нашего кода вызываем proxy-объект, а передаем его куда-то. Контролируя таким образом общение двух независимых от нас объектов.

Виды прокси по назначению:

  • Протоколирующий прокси: сохраняет в лог все вызовы “Субъекта” с их параметрами.
  • Удаленный заместитель (remote proxies): обеспечивает связь с “Субъектом”, который находится в другом адресном пространстве или на удаленной машине. Также может отвечать за кодирование запроса и его аргументов и отправку закодированного запроса реальному “Субъекту”.
  • Виртуальный заместитель (virtual proxies): обеспечивает создание реального “Субъекта” только тогда, когда он действительно понадобится. Также может кэшировать часть информации о реальном “Субъекте”, чтобы отложить его создание.
  • Копировать-при-записи: обеспечивает копирование “субъекта” при выполнении клиентом определенных действий (частный случай “виртуального прокси”).
  • Защищающий заместитель (protection proxies): может проверять, имеет ли вызывающий объект необходимые для выполнения запроса права.
  • Кэширующий прокси: обеспечивает временное хранение результатов расчета до отдачи их множественным клиентам, которые могут разделить эти результаты.
  • Экранирующий прокси: защищает “Субъект” от опасных клиентов (или наоборот).
  • Синхронизирующий прокси: производит синхронизированный контроль доступа к “Субъекту” в асинхронной многопоточной среде.
  • “Умная” ссылка (smart reference proxy): производит дополнительные действия, когда на “Субъект” создается ссылка, например, рассчитывает количество активных ссылок на “Субъект”.

2.4 Bridge

Шаблон Мост (Bridge) — структурный шаблон проектирования, используемый чтобы “разделять абстракцию и реализацию так, чтобы они могли изменяться независимо”.

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

Мост (Bridge)

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

Рассмотрим такую абстракцию как фигура. Существует множество типов фигур, каждая со своими свойствами и методами. Однако есть что-то, что объединяет все фигуры. Например, каждая фигура должна уметь рисовать себя, масштабироваться и так далее.

В то же время рисование графики может отличаться в зависимости от типа ОС или графической библиотеки. Фигуры должны иметь возможность рисовать себя в различных графических средах. Но реализовывать в каждой фигуре все способы рисования или модифицировать фигуру каждый раз при изменении способа рисования непрактично.

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

Связь, изображаемая стрелкой на диаграммах, может иметь 2 смысла: а) “разновидность”, в соответствии с принципом подстановки Лисков и б) одна из возможных реализаций абстракции. Обычно в языках используется наследование для реализации как а), так и б), что приводит к разбуханию иерархий классов.

Мост служит именно для решения этой проблемы: объекты создаются парами из объекта класса иерархии А и иерархии B, наследование внутри иерархии А имеет смысл “разновидность” по Лисков, а для понятия “реализация абстракции” используется ссылка из объекта A в парный ему объект B.

2.5 Facade

Шаблон Фасад (Facade) — структурный шаблон проектирования, позволяющий скрыть сложность системы путем сведения всех возможных внешних вызовов к одному объекту, делегирующему их соответствующим объектам системы.

Шаблон Фасад (Facade)

Как обеспечить унифицированный интерфейс с набором разрозненных реализаций или интерфейсов, например, с подсистемой, если нежелательно сильное связывание с этой подсистемой или реализация подсистемы может измениться?

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

Реализация других компонентов подсистемы закрыта и не видна внешним компонентам. Фасадный объект обеспечивает реализацию GRASP паттерна Устойчивый к изменениям с точки зрения защиты от изменений в реализации подсистемы.

Важно! Этот шаблон применяется, когда мы хотим полностью скрыть какую-то группу объектов и всю коммуникацию с ними пропустить через наш объект. Если же вы просто хотите обеспечить некоторый контроль процесса коммуникации объектов и скрывать их не обязательно, то лучше воспользоваться паттерном Proxy.

Комментарии (18)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Роман Уровень 88
8 декабря 2024
Вот здесь можно найти примеры ко всем паттернам.
Дмитрий Саргаев Уровень 76 Expert
14 октября 2023
Слово "улучшить" во второй задаче, конечно, не совсем к месту. Скорее "исправить". Это я быстро нашел, даже несмотря на сбивающее с толку "улучшить", ведь улучшают обычно то, что уже нормально работает. А тут явно не нормально работает. Но это ладно... А вот в первой задаче "усовершенствовать" - это, видимо, имеется ввиду "сделать так, чтобы программа не работала бесконечно"? Не понятно, что на самом деле от тебя хотят. Совершенствовать этот простой код, очевидно, можно до бесконечности, но это не имеет ничего общего с тем, что надо сделать) Может это исключительно мое восприятие, но не высказаться не мог)
Ольга Николенко Уровень 109 Expert
12 марта 2024
Согласна, учитывая знания, что мы получаем в последних лекциях, в этих примерах надо менять абсолютно все, но какие "улучшения" подразумеваются и насколько полезно этим заниматься, по сравнению, например, с чтением книги по паттернам или самостоятельно придуманными примерами - не понятно. Но сами задачи нравятся, как простые примеры для понимания сути паттерна.
Дмитрий Саргаев Уровень 76 Expert
13 октября 2023
Может я чего-то не понимаю...
Дмитрий Саргаев Уровень 76 Expert
13 октября 2023
Оказывается, package protected ему не нравится... Отняли попытку у меня на ровном месте)
Олег Уровень 111 Expert
21 августа 2023
Да уж, подловили создатели задачи на модификаторе доступа класса Creature, долго не мог понять упорное нежелание Валидатора принимать правильное решение, а оказался маленький нюанс не учёл.
Max Dudin Уровень 6 Expert
8 августа 2023
ура товарищи... опять задачки после столь долгого перерыва =))
Dmitriy Уровень 95 Expert
24 июля 2023
У меня во второй задаче накапливается ошибка: Итого: 100.0; Состав: тесто, помидоры, сыр Итого: 120.0; Состав: тесто, помидоры, сыр, курица Итого: 145.0; Состав: тесто, помидоры, сыр, курица, колбаса Итого: 160.0; Состав: тесто, помидоры, сыр, курица, колбаса, руккола Проверил ответ. Он совпадает с моим решением Возможно надо в конструктор, для кадкой новой пиццы, передавать новый объект: new SimplePizza()
Надежда Уровень 104 Expert
26 июля 2023
Никакой ошибки нет. В main методе четко указано, что должна образоваться цепочка из пицц: Pizza pizza = new SimplePizza(); printInfo(pizza); pizza = new WithChicken(pizza); printInfo(pizza); pizza = new WithSausage(pizza); printInfo(pizza); pizza = new WithArugula(pizza); printInfo(pizza); Сначала мы печатаем инфу по SimplePizza. Потом "делаем" новую пиццу с курицей WithChicken, в основе которой SimplePizza и печатаем инфу (поэтому у нас добавляется к списку ингредиентов базовой пиццы курица и увеличивается стоимость пиццы). Потом "делаем" новую пиццу с колбасой WithSausage, в основе которой уже пицца с курицей WithChicken и печатаем инфу (поэтому у нас добавляется к списку ингредиентов пиццы с курицей WithChicken колбаса и увеличивается стоимость пиццы). И т.д. по цепочке. Можно реализовать и по-другому, если хотите, чтобы в основе всех новых видов пицц была SimplePizza: Pizza pizza = new SimplePizza(); printInfo(pizza); Pizza pizzaWithChicken = new WithChicken(pizza); printInfo(pizzaWithChicken); Pizza pizzaWithSausage = new WithSausage(pizza); printInfo(pizzaWithSausage); Pizza pizzaWithArugula = new WithArugula(pizza); printInfo(pizzaWithArugula); Тогда output будет такой: Итого: 100.0; Состав: тесто, помидоры, сыр Итого: 120.0; Состав: тесто, помидоры, сыр, курица Итого: 125.0; Состав: тесто, помидоры, сыр, колбаса Итого: 115.0; Состав: тесто, помидоры, сыр, руккола
Виктория Уровень 111
19 мая 2023
Еще не решала. Но наконец-то задачи!🎉🎉
Денис Уровень 2 Expert
3 апреля 2023
Прям очень классные задачи, понятный код который быстро читается и хорошее описание. не потратил ни на одну больше 15 минут. Это круто и паттерн более - менее понятен. Спасибо команде JR.
Михаил Уровень 2
14 февраля 2023
а где вы задачи видите? Вижу в комментах их обсуждают, но я никаких задач в этом курсе не вижу, только лекции.
Misha Saharin Уровень 111 Expert
5 марта 2023
задачи видны для студентов курса JavaRush
Александр Уровень 111 Expert
30 октября 2022
Понравились задачи, много времени ушло чтобы сперва прочитать код и понять, что там происходит Surprise, анонимус! показалось самой сложной и запутанной.