PATTERNS Flashcards

1
Q

Что такое «шаблон проектирования»?

A

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

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

Плюсы:
* упрощение разработки за счет готовых абстракций, Шаблоны проектирования уже проверены временем и опытом, поэтому использование их может уменьшить количество ошибок и упростить разработку.
* облегчение коммуникации между разработчиками.
* Увеличение переносимости - Шаблоны проектирования могут быть использованы в разных проектах и на разных языках программирования, что позволяет увеличить переносимость кода.
* Знание ООП и принципов ООП не позволит писать хороший код, нужно применять паттерны, которые были сформулированы на принципах ООП
Минусы:
* слепое следование некоторому шаблону может привести к усложнению программы;
* желание попробовать некоторый шаблон в деле без особых на то оснований.
* Перфекционизм - Разработчики могут стать слишком зависимыми от шаблонов проектирования и стараться применять их везде, даже там, где это не нужно, что может привести к избыточности кода.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Зачем знать паттерны?

A

Вы можете вполне успешно работать, не зная ни одного паттерна. Более того, вы могли уже не раз реализовать какой-то из паттернов, даже не подозревая об этом.

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

  • Проверенные решения. Вы тратите меньше времени, используя готовые решения, вместо повторного изобретения велосипеда. До некоторых решений вы смогли бы додуматься и сами, но многие могут быть для вас открытием.
  • Стандартизация кода. Вы делаете меньше просчётов при проектировании, используя типовые унифицированные решения, так как все скрытые проблемы в них уже давно найдены.
  • Общий программистский словарь. Вы произносите название паттерна, вместо того, чтобы час объяснять другим программистам, какой крутой дизайн вы придумали и какие классы для этого нужны.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Назовите основные характеристики шаблонов.

A

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Назовите три основные группы паттернов.

A

Порождающие – абстрагируют процесс создание экземпляра, делегируя этот процесс другому объекту.
Они позволяют сделать систему независимой от способа создания и композиции объектов и избежать внесения в программу лишних зависимостей.
* Фабричный метод (Factory method) - определяет интерфейс для создания объектов, но позволяет подклассам выбрать класс создаваемого экземпляра.
* Абстрактная фабрика (Abstract factory) - предоставляет интерфейс для создания связанных объектов, без указания конкретных классов.
* Одиночка (Singleton) - гарантирует, что у класса есть только один экземпляр, и обеспечивает доступ к нему через глобальную точку доступа.
* Строитель (Builder) - разделяет процесс создания сложного объекта на более простые шаги и обеспечивает контроль над этим процессом.
* Прототип (Prototype) - используется для создания новых объектов путем копирования существующих объектов.

Структурные – отвечают за построение удобной в поддержке системы зависимостей между объектами с целью создания более функциональных структур.
* Адаптер (Adapter) - позволяет интерфейсу одного класса быть использованным как интерфейс другого класса.
* Мост (Bridge) - разделяет абстракцию от ее реализации, позволяя им изменяться независимо друг от друга.
* Декоратор (Decorator) - динамически добавляет новую функциональность к объекту, не изменяя его исходного класса.
* Фасад (Facade) - предоставляет простой интерфейс для сложной системы, упрощая взаимодействие клиентов с системой.
* Компоновщик (Composite) - позволяет обрабатывать отдельные объекты и их группы одинаково.

Поведенческие – заботятся об эффективной коммуникации между объектами.
* Цепочка ответственности (Chain of Responsibility) - позволяет передавать запросы по цепочке объектов, пока один из них не обработает запрос.
* Команда (Command) - инкапсулирует запрос в виде объекта, что позволяет задавать параметры для запроса, ставить запросы в очередь и отменять операции.
* Итератор (Iterator) - предоставляет способ последовательного доступа к элементам объекта без раскрытия его внутренней структуры.
* Состояние (State) - позволяет объекту изменять свое поведение в зависимости от своего внутреннего состояния
* Наблюдатель (Observer) - позволяет объектам оповещать другие объекты об изменениях своего состояния, не зная, какие объекты конкретно будут оповещены.

Паттерны архитектуры (Architectural patterns):
Архитектурные паттерны (Architectural patterns) - определяют общую архитектуру системы и ее компонентов. Они используются для определения общей структуры приложения.

  • Модель-вид-контроллер (Model-View-Controller, MVC) - разделяет приложение на три основные компоненты: модель данных, представление и контроллер, обеспечивая лучшую организацию и управляемость кода.
  • Слой сервисов (Service Layer) - представляет собой слой абстракции, который обеспечивает логику приложения и взаимодействие между уровнями, скрывая подробности реализации от других слоев.
  • Фронт-контроллер (Front Controller) - представляет собой компонент, который обрабатывает все запросы пользователя, прежде чем они будут переданы на обработку другим компонентам приложения.
  • Инверсия управления (Inversion of Control, IoC) - представляет собой шаблон проектирования, который переносит управление созданием и связыванием объектов на специальный контейнер (IoC-контейнер), чтобы снизить связанность между компонентами и упростить тестирование и расширение кода.
  • Микросервисы (Microservices) - представляют собой архитектурный подход, при котором приложение разбивается на множество маленьких сервисов, каждый из которых отвечает за конкретную функциональность и может разрабатываться и масштабироваться независимо от других сервисов.

Основные – основные строительные блоки, используемые для построения других шаблонов. Например, интерфейс.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Расскажите про паттерн Одиночка (Singleton).

A

Singleton pattern в Java - это порождающий шаблон проектирования, который гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к этому экземпляру.

Реализация Singleton в Java включает в себя создание приватного конструктора класса, чтобы запретить создание экземпляров класса извне, а также создание статической переменной, которая будет хранить единственный экземпляр класса. Затем создается статический метод, getInstance(). Он либо создает объект, либо возвращает существующий объект, если он уже был создан.

public class Singleton {
   private static Singleton instance;

   private Singleton() {}

   static {
      instance = new Singleton();
   }

   public static Singleton getInstance() {
      return instance;
   }
}

Singleton может использоваться в различных областях, например:

  • Работа с конфигурационными файлами - Singleton может быть использован для загрузки конфигурационных данных в приложении, что обеспечивает единственную точку доступа к этим данным во всем приложении.
  • Работа с базой данных - Singleton может быть использован для создания единственного подключения к базе данных, что обеспечивает более эффективное использование ресурсов и улучшает производительность приложения.
  • Создание логгера - Singleton может быть использован для создания логгера, который будет использоваться во всем приложении. Это позволяет управлять уровнем логирования и записью логов в единственном месте.
  • **Кэширование данных **- Singleton может быть использован для создания кэша данных, который будет использоваться во всем приложении. Это позволяет уменьшить время доступа к данным и улучшить производительность приложения.
  • Создание фабрики объектов - Singleton может быть использован для создания фабрики объектов, которая будет создавать объекты определенного типа во всем приложении.

Некоторые из фреймворков, которые используют Singleton:
* Spring Framework - Singleton используется по умолчанию для создания бинов (объектов), которые управляются контейнером Spring.
* Hibernate - Singleton может использоваться для создания фабрики сессий, которая будет использоваться для создания сессий для работы с базой данных.
* Log4j - Singleton используется для создания объекта логгера, который будет использоваться для записи логов в приложении.
* Junit - Singleton может использоваться для создания объекта TestRunner, который будет использоваться для запуска тестов в Junit.
* Apache Commons Pool - Singleton может использоваться для создания пула объектов, который будет использоваться для повторного использования объектов и уменьшения нагрузки на систему.

Плюсы использования паттерна Singleton в Java:

  • Гарантирует наличие единственного экземпляра класса.
  • Предоставляет глобальную точку доступа к этому экземпляру, что упрощает управление объектами.
  • Позволяет использовать ленивую инициализацию, т.е. создание объекта только при первом вызове метода getInstance(), что может быть полезно для экономии ресурсов.
  • Можно наследовать Singleton-классы, что упрощает создание подклассов с единственным экземпляром.

Минусы использования паттерна Singleton в Java:

  • Уменьшает гибкость кода, т.к. создание единственного экземпляра класса жестко заложено в коде, и нельзя создать дополнительные экземпляры, если это понадобится.
  • Может привести к созданию глобального состояния, которое может быть изменено в любом месте программы, что усложняет отладку и тестирование приложения.
  • Может привести к проблемам с многопоточностью, если не обеспечена правильная синхронизация доступа к единственному экземпляру класса.
  • Нарушает принцип единой ответственности, так как
    1) Несет функционал
    2) Гарантирует наличие одной сущности
    3) Обеспечивает единую точку доступа к этой сущности
  • Требует постоянного создания Mock-объектов при юнит-тестировании.

Какие реализации паттерна Singleton вы знаете?
Жадные:
1) Статическое поле и метод доступа (Static field and accessor)
2) Объект перечисления (Enum)
Ленивые:
1) Синхронизированный метод доступа (Synchronized accessor)
2) Блокировка с двойной проверкой и volatile (Double-checked locking + volatile)
3) Внутренний статический класс Holder (On demand Holder).

Шаги реализации
1. Добавьте в класс приватное статическое поле, которое будет содержать одиночный объект.
2. Объявите статический создающий метод, который будет использоваться для получения одиночки.
3. Добавьте «ленивую инициализацию» (создание объекта при первом вызове метода) в создающий метод одиночки.
4. Сделайте конструктор класса приватным.
5. В клиентском коде замените вызовы конструктора одиночка вызовами его создающего метода.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Расскажите про паттерн Строитель (Builder).

A

Паттерн Строитель (Builder) - это Порождающий паттерн проектирования, который используется для создания сложных объектов с различными свойствами. Он позволяет создавать объекты пошагово, обеспечивая контроль над каждой стадией создания объекта. А значит, больше не нужно пытаться «запихнуть» в конструктор все возможные опции продукта.
Паттерн предлагает вынести конструирование объекта за пределы его собственного класса, поручив это дело отдельным объектам, называемым строителями.

Название паттерна: Строитель (Builder).

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

Задача, которую шаблон позволяет решить: шаблон Строитель позволяет создавать объекты, состоящие из множества взаимосвязанных компонентов, при этом упрощая процесс их создания и обеспечивая гибкость в выборе компонентов и порядке их создания.

Способ решения: для решения задачи создания сложных объектов, паттерн Строитель предлагает создание отдельного класса-строителя (Builder), который содержит методы для пошагового создания объекта. Чтобы создать объект, вам нужно поочерёдно вызывать методы строителя. Причём не нужно запускать все шаги, а только те, что нужны для производства объекта определённой конфигурации.
Кроме того, для создания объекта используется класс-директор (Director), который определяет порядок вызова методов класса-строителя.

Участники:
* класс-строитель (Builder)
* класс-директор (Director)
* конечный объект (Product), который является результатом работы шаблона.

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

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

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

В Java директор может быть реализован как отдельный класс, который получает объект-строитель в качестве аргумента конструктора и вызывает его методы по порядку.

Использование директора позволяет упростить процесс конструирования сложного объекта, так как клиентский код может просто создать объект директора и вызывать его методы для создания объектов, не беспокоясь о деталях конструирования. Также это позволяет улучшить читаемость кода, так как последовательность вызовов методов строителя определяется в одном месте - в директоре.

Шаги реализации:
1. Убедитесь в том, что создание разных представлений объекта можно свести к общим шагам.
2. Опишите эти шаги в общем интерфейсе строителей.
3. Для каждого из представлений объекта-продукта создайте по одному классу-строителю и реализуйте их методы строительства.
4. Не забудьте про метод получения результата. Обычно конкретные строители определяют собственные методы получения результата строительства. Вы не можете описать эти методы в интерфейсе строителей, поскольку продукты не обязательно должны иметь общий базовый класс или интерфейс. Но вы всегда сможете добавить метод получения результата в общий интерфейс, если ваши строители производят однородные продукты с общим предком.
5. Подумайте о создании класса директора. Его методы будут создавать различные конфигурации продуктов, вызывая разные шаги одного и того же строителя.
6. Клиентский код должен будет создавать и объекты строителей, и объект директора. Перед началом строительства клиент должен связать определённого строителя с директором. Это можно сделать либо через конструктор, либо через сеттер, либо подав строителя напрямую в строительный метод директора.
7. Результат строительства можно вернуть из директора, но только если метод возврата продукта удалось поместить в общий интерфейс строителей. Иначе вы жёстко привяжете директора к конкретным классам строителей.

Преимущества
* Позволяет создавать продукты пошагово.
* Позволяет использовать один и тот же код для создания различных продуктов.
* Изолирует сложный код сборки продукта от его основной бизнес-логики.

Недостатки

  • Усложняет код программы из-за введения дополнительных классов.
  • Клиент будет привязан к конкретным классам строителей, так как в интерфейсе директора может не быть метода получения результата.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Расскажите про паттерн Фабричный метод (Factory Method).

A

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

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

Объекты всё равно будут создаваться при помощи new, но делать это будет фабричный метод. Таким образом можно переопределить фабрчный метод в подклассе, чтобы изменить тип создаваемого продукта.

Допустим, у нас есть некоторый суперкласс, который определяет интерфейс для создания объектов, но сам не определяет конкретный класс объекта. Вместо этого он оставляет реализацию создания объекта подклассам, которые наследуются от этого суперкласса.
В таком случае, каждый подкласс может определить свой собственный класс объекта, который будет создаваться. Это позволяет подклассам изменять тип создаваемых объектов. Таким образом, мы можем создавать объекты разных типов, используя один и тот же интерфейс создания объектов.
Например, представьте, что у нас есть суперкласс “Фабрика пиццы”, который определяет интерфейс для создания пиццы. Мы можем создать подклассы, которые реализуют этот интерфейс, и каждый из них может определять свой собственный тип пиццы. Таким образом, мы можем создавать различные типы пицц, используя один и тот же интерфейс “Фабрика пиццы”.

Фабричный метод применяется, когда заранее неизвестны типы и зависимости объектов, с которыми должен работать ваш код.

Фабричный метод отделяет код производства продуктов от остального кода, который эти продукты использует.

Имя: Фабричный метод (Factory Method).

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

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

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

Участники:

  • Product (Продукт) – интерфейс для объектов, которые фабрика создает.
  • ConcreteProduct (Конкретный продукт) – классы, которые реализуют интерфейс Product.
  • Creator (Создатель) – абстрактный класс или интерфейс, который определяет метод FactoryMethod для создания объекта. Этот метод может быть абстрактным, либо иметь реализацию по умолчанию.
  • ConcreteCreator (Конкретный создатель) – классы, которые наследуются от Creator и реализуют FactoryMethod для создания объектов.

**Следствия от использования шаблона: **позволяет улучшить расширяемость кода, избежать жестких зависимостей от конкретных классов, а также повысить уровень абстракции в приложении. При этом может возникнуть некоторая избыточность кода, так как для каждого нового типа продукта нужно создавать новый подкласс ConcreteProduct и ConcreteCreator.

Шаги реализации
1. Приведите все создаваемые продукты к общему интерфейсу.
2. В классе, который производит продукты, создайте пустой фабричный метод. В качестве возвращаемого типа укажите общий интерфейс продукта.
3. Затем пройдитесь по коду класса и найдите все участки, создающие продукты. Поочерёдно замените эти участки вызовами фабричного метода, перенося в него код создания различных продуктов.
В фабричный метод, возможно, придётся добавить несколько параметров, контролирующих, какой из продуктов нужно создать.
На этом этапе фабричный метод, скорее всего, будет выглядеть удручающе. В нём будет жить большой условный оператор, выбирающий класс создаваемого продукта. Но не волнуйтесь, мы вот-вот исправим это.
4. Для каждого типа продуктов заведите подкласс и переопределите в нём фабричный метод. Переместите туда код создания соответствующего продукта из суперкласса.
5. Если создаваемых продуктов слишком много для существующих подклассов создателя, вы можете подумать о введении параметров в фабричный метод, которые позволят возвращать различные продукты в пределах одного подкласса.
Например, у вас есть класс Почта с подклассами АвиаПочта и НаземнаяПочта, а также классы продуктов Самолёт, Грузовик и Поезд. Авиа соответствует Самолётам, но для НаземнойПочты есть сразу два продукта. Вы могли бы создать новый подкласс почты для поездов, но проблему можно решить и по-другому. Клиентский код может передавать в фабричный метод НаземнойПочты аргумент, контролирующий тип создаваемого продукта.
6. Если после всех перемещений фабричный метод стал пустым, можете сделать его абстрактным. Если в нём что-то осталось — не беда, это будет его реализацией по умолчанию.

Фабричный метод можно рассматривать как частный случай Шаблонного метода. Кроме того, Фабричный метод нередко бывает частью большого класса с Шаблонными методами.

Преимущества использования паттерна Фабричный метод в Java:

  • уменьшение связности между классами, т.к. создание объекта вынесено в отдельный класс;
  • возможность добавлять новые подклассы для создания объектов, не изменяя код клиентского класса;
  • повышение гибкости приложения за счет использования интерфейса.
  • инкапсулирует создание объектов, предлагая единый интерфейс для этого процесса и тип возвращаемого объекта может варьироваться в зависимости от входных параметров.
  • Реализует принцип открытости/закрытости.

Недостатки использования паттерна Фабричный метод в Java:
* не масштабируются для большого кол-ва необязательных параметров.

Зачем фабрики оформляются в виде статических методов?

Чтобы метод create можно было вызывать и без создания экземпляра объекта. С другой стороны,
теряется возможность субклассирования и изменения поведения метода create.

Пример: SessionFactory в Hibernate.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Расскажите про паттерн Абстрактная фабрика (Abstract Factory).

A

Шаблон “абстрактная фабрика” (Abstract Factory) является порождающим паттерном проектирования, который предоставляет интерфейс для создания семейств связанных объектов без указания их конкретных классов. Он позволяет создавать объекты с определенными интерфейсами, не привязываясь к их конкретным реализациям, тем самым обеспечивая гибкость и удобство при изменении логики создания объектов.
Абстрактная фабрика создает интерфейс, группирующий остальные фабрики, которые логически связанны друг с другом. Это своег орода абстракция для фабрики и фабричного метода

Имя: Abstract Factory

Назначение: Предоставляет интерфейс для создания семейств связанных объектов без указания их конкретных классов.

Задача: Обеспечить создание семейства связанных объектов, при этом не зависеть от их конкретных реализаций.

Способ решения: Абстрактная фабрика определяет интерфейс для создания семейств связанных объектов, каждый из которых имеет общий интерфейс, но может иметь свою конкретную реализацию.

Участники:

  • Абстрактная фабрика: определяет интерфейс для создания объектов.
  • Конкретная фабрика: реализует интерфейс Абстрактной фабрики для создания конкретных объектов.
  • Абстрактный продукт: определяет общий интерфейс продуктов, создаваемых Абстрактной фабрикой.
  • Конкретный продукт: реализует интерфейс Абстрактного продукта.

Следствия: Использование паттерна “абстрактная фабрика” обеспечивает гибкость и удобство при изменении логики создания объектов, позволяет создавать объекты с определенными интерфейсами, не привязываясь к их конкретным реализациям.

Абстрактная фабрика определяет интерфейс для создания семейства связанных объектов, таких как объекты пиццы и их ингредиенты. Конкретные фабрики реализуют этот интерфейс и создают конкретные объекты. Таким образом, использование Абстрактной фабрики позволяет легко заменять семейства продуктов в зависимости от контекста приложения.

Применимость
Когда бизнес-логика программы должна работать с разными видами связанных друг с другом продуктов, не завися от конкретных классов продуктов.

  • Абстрактная фабрика скрывает от клиентского кода подробности того, как и какие конкретно объекты будут созданы. Но при этом клиентский код может работать со всеми типами создаваемых продуктов, поскольку их общий интерфейс был заранее определён.

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

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

Шаги реализации:
1. Создайте таблицу соотношений типов продуктов к вариациям семейств продуктов.
2. Сведите все вариации продуктов к общим интерфейсам.
3. Определите интерфейс абстрактной фабрики. Он должен иметь фабричные методы для создания каждого из типов продуктов.
4. Создайте классы конкретных фабрик, реализовав интерфейс абстрактной фабрики. Этих классов должно быть столько же, сколько и вариаций семейств продуктов.
5. Измените код инициализации программы так, чтобы она создавала определённую фабрику и передавала её в клиентский код.
6. Замените в клиентском коде участки создания продуктов через конструктор вызовами соответствующих методов фабрики.

Преимущества
* Гарантирует сочетаемость создаваемых продуктов.
* Избавляет клиентский код от привязки к конкретным классам продуктов.
* Выделяет код производства продуктов в одно место, упрощая поддержку кода.
* Упрощает добавление новых продуктов в программу.
* Реализует принцип открытости/закрытости.
Недостатки
* Усложняет код программы из-за введения множества дополнительных классов.
* Требует наличия всех типов продуктов в каждой вариации.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Отличия между фабричным методом и абстрактной фабрикой

A
  1. Фабричный метод создает один продукт, а Абстрактная фабрика создает семейство связанных продуктов.
  2. Фабричный метод использует наследование, чтобы делегировать создание конкретных продуктов дочерним классам, а Абстрактная фабрика использует композицию объектов для создания продуктов.
  3. Фабричный метод может быть реализован в виде статического метода, а Абстрактная фабрика требует создания объекта фабрики для создания продуктов.
  4. Фабричный метод создает продукт из одного класса, а Абстрактная фабрика создает продукты из нескольких взаимосвязанных классов.
  5. Фабричный метод может быть переопределен в подклассах для создания различных вариаций продуктов, а Абстрактная фабрика может быть расширена путем добавления новых классов продуктов и соответствующих фабрик.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Расскажите про паттерн Прототип (Prototype).

A

Порождающий паттерн проектирования, который позволяет копировать объекты, не вдаваясь в подробности их реализации.
Он вводит общий интерфейс с методом clone для всех объектов, поддерживающих клонирование.
Реализация этого метода в разных классах очень схожа.
Метод создаёт новый объект текущего класса и копирует в него значения всех полей собственного объекта.

Имя: Прототип (Prototype)

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

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

Способ решения: Шаблон Прототип предлагает создание интерфейса-прототипа, который определяет метод клонирования объекта. Затем создаются классы, реализующие этот интерфейс, которые могут создавать новые объекты на основе уже существующих прототипов путем клонирования.

Участники:

  • Клиент: создает новые объекты, используя прототипы.
  • Прототип: определяет интерфейс клонирования объектов.
  • Конкретный прототип: реализует интерфейс клонирования объекта и содержит конкретную реализацию клонирования объекта.

Следствия от использования шаблона:
* Уменьшение затрат на производство объектов путем использования готовых прототипов.
* Увеличение эффективности разработки благодаря упрощенному процессу создания объектов.
* Гибкость в создании новых объектов, которые могут быть созданы на основе уже существующих прототипов.
* Возможность создания новых объектов без необходимости явного указания класса.
* Возможность изменения поведения создаваемых объектов путем изменения конкретных прототипов.

Шаги реализации паттерна Прототип (Prototype) могут быть следующими:

  1. Создать абстрактный класс или интерфейс, который определяет метод клонирования объекта. Обычно этот метод должен создавать копию объекта и возвращать ее.
  2. Создать класс-прототип, который реализует интерфейс клонирования и представляет собой объект, который нужно клонировать.
  3. Если требуется, создать несколько конкретных классов-прототипов, которые наследуются от базового класса-прототипа.
  4. Создать класс, который будет использовать прототипы для создания новых объектов. Этот класс будет содержать методы для регистрации прототипов и создания новых объектов на основе этих прототипов.
  5. В клиентском коде создать объекты, используя методы класса, созданного на шаге 4.
  6. Проверить, что созданные объекты идентичны прототипам, которые использовались для их создания.

Плюсы использования паттерна Прототип:

  • Уменьшение количества классов. Когда нужно создавать большое количество объектов с похожими свойствами, использование шаблона Прототип может значительно уменьшить количество классов в программе, так как не нужно создавать классы для каждого конкретного объекта.
  • Позволяет клонировать объекты, не привязываясь к их конкретным классам.
  • Ускорение создания объектов. Использование шаблона Прототип позволяет ускорить создание объектов за счет клонирования уже существующих объектов.
  • Гибкость. Шаблон Прототип позволяет динамически создавать новые объекты на основе уже существующих, что обеспечивает гибкость и удобство в работе.

Минусы использования паттерна Прототип:

  • Сложно клонировать составные объекты, имеющие ссылки на другие объекты.
  • Проблемы с безопасностью. Если объекты содержат конфиденциальную информацию, клонирование может привести к раскрытию этой информации. Эту проблему можно решить путем реализации защиты конфиденциальных данных в клонированном объекте.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Расскажите про паттерн Адаптер (Adapter).

A

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

Это объект-переводчик, который трансформирует интерфейс или данные одного объекта в такой вид, чтобы он стал понятен другому объекту.

При этом адаптер оборачивает один из объектов, так что другой объект даже не знает о наличии первого.

1) Адаптер имеет интерфейс, который совместим с первым объектом и содержит второй объект.
2) Поэтому на объекте адаптера можно вызывать методы первого объекта.
3) Адаптер получает эти вызовы и перенаправляет их второму объекту, но уже в том формате и последовательности, которые понятны второму объекту.

Назначение: Паттерн Адаптер позволяет объединять несовместимые интерфейсы, позволяя объектам работать вместе, которые ранее не могли взаимодействовать из-за несовместимости их интерфейсов.

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

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

Участники:
* Клиент: объект, который использует другой объект через интерфейс.
* Интерфейс, который должен быть использован клиентом.
* Адаптируемый объект: объект, который должен быть использован клиентом, но имеет неподходящий интерфейс.
* Адаптер: класс, который реализует интерфейс, который должен быть использован клиентом, и преобразует вызовы к адаптируемому объекту в соответствующие вызовы.

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

Шаги реализации
1. Убедитесь, что у вас есть два класса с несовместимыми интерфейсами:

  • полезный сервис — служебный класс, который вы не можете изменять (он либо сторонний, либо от него зависит другой код);
  • один или несколько клиентов — существующих классов приложения, несовместимых с сервисом из-за неудобного или несовпадающего интерфейса.
  1. Опишите клиентский интерфейс, через который классы приложения смогли бы использовать класс сервиса.
  2. Создайте класс адаптера, реализовав этот интерфейс.
  3. Поместите в адаптер поле, которое будет хранить ссылку на объект сервиса. Обычно это поле заполняют объектом, переданным в конструктор адаптера. В случае простой адаптации этот объект можно передавать через параметры методов адаптера.
  4. Реализуйте все методы клиентского интерфейса в адаптере. Адаптер должен делегировать основную работу сервису.
  5. Приложение должно использовать адаптер только через клиентский интерфейс. Это позволит легко изменять и добавлять адаптеры в будущем.

Преимущества
* Отделяет и скрывает от клиента подробности преобразования различных интерфейсов.

Недостатки
* Усложняет код программы из-за введения дополнительных классов.

Ниже приведены некоторые примеры использования Адаптера в Java:

  • java.io.InputStreamReader - это пример класса-адаптера, который преобразует InputStream в Reader.
  • java.util.Arrays#asList() - метод asList() использует адаптер для преобразования массива в список.
  • java.util.Collections#list()- метод list() также использует адаптер для преобразования массива в список.
  • java.util.stream.Stream - этот класс предоставляет методы адаптеры для преобразования коллекций, массивов и других источников данных в поток данных.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Расскажите про паттерн Декоратор (Decorator).

A

Декоратор — это структурный паттерн проектирования, который позволяет динамически добавлять объектам новую функциональность, оборачивая их в полезные «обёртки».

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

Имя: Декоратор (Decorator).

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

Задача: Декоратор используется для расширения функциональности объектов без необходимости изменять сам объект. Это особенно полезно в тех случаях, когда необходимо добавить новое поведение объекту, но не хочется создавать множество подклассов для каждой комбинации поведения.

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

Участники:
* Компонент (Component): это базовый класс, который определяет интерфейс для всех объектов, которые могут быть декорированы.
* Конкретный компонент (Concrete Component): это базовый объект, который может быть декорирован.
* Декоратор (Decorator): это базовый класс для всех декораторов. Он содержит ссылку на объект типа Component и определяет интерфейс, который соответствует интерфейсу Component.
* Конкретный декоратор (Concrete Decorator): это классы-декораторы, которые добавляют новую функциональность объекту.

Следствия от использования шаблона:
Использование паттерна Декоратор позволяет добавлять новую функциональность объекту, не изменяя его основной структуры. Это упрощает поддержку кода, позволяет избежать создания множества подклассов для каждой комбинации поведения. Кроме того, Декоратор улучшает модульность кода, поскольку каждый декоратор может быть использован независимо от других. Однако следует учитывать, что использование слишком многих декораторов может привести к перегрузке объекта.

Шаги реализации
1. Убедитесь, что в вашей задаче есть один основной компонент и несколько опциональных дополнений или надстроек над ним.
2. Создайте интерфейс компонента, который описывал бы общие методы как для основного компонента, так и для его дополнений.
3. Создайте класс конкретного компонента и поместите в него основную бизнес-логику.
4. Создайте базовый класс декораторов. Он должен иметь поле для хранения ссылки на вложенный объект-компонент. Все методы базового декоратора должны делегировать действие вложенному объекту.
5. И конкретный компонент, и базовый декоратор должны следовать одному и тому же интерфейсу компонента.
6. Теперь создайте классы конкретных декораторов, наследуя их от базового декоратора. Конкретный декоратор должен выполнять свою добавочную функцию, а затем (или перед этим) вызывать эту же операцию обёрнутого объекта.
7. Клиент берёт на себя ответственность за конфигурацию и порядок обёртывания объектов.

Преимущества
* Большая гибкость, чем у наследования.
* Позволяет добавлять обязанности на лету.
* Можно добавлять несколько новых обязанностей сразу.
* Позволяет иметь несколько мелких объектов вместо одного объекта на все случаи жизни.

Недостатки
* Трудно конфигурировать многократно обёрнутые объекты.
* Обилие крошечных классов.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Расскажите про паттерн Заместитель (Proxy).

A

Заместитель — это структурный паттерн проектирования, который позволяет подставлять вместо реальных объектов специальные объекты-заменители. Эти объекты перехватывают вызовы к оригинальному объекту, позволяя сделать что-то до или после передачи вызова оригиналу.

Клиент не знает, что общается с прокси, он просто обращается к объкту общего для прокси и базового объекта интерфейсу.

Заместитель предлагает создать новый класс-дублёр, имеющий тот же интерфейс, что и оригинальный служебный объект. При получении запроса от клиента объект-заместитель сам бы создавал экземпляр служебного объекта, выполняя промежуточную логику, которая выполнялась бы до (или после) вызовов этих же методов в настоящем объекте.

Имя: Заместитель (Proxy).

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

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

Способ решения: Паттерн Заместитель предлагает создание суррогатного объекта, который выступает в роли заместителя для реального объекта. Этот заместитель может иметь такой же интерфейс, как и реальный объект, что позволяет использовать его вместо него без каких-либо изменений в коде. При этом заместитель может выполнять определенные действия до и после обращения к реальному объекту, например, проверять права доступа или откладывать его создание до момента, когда это будет необходимо.

Участники: В паттерне Заместитель участвуют следующие сущности:

  • Subject: определяет общий интерфейс для Proxy и RealSubject. Поэтому Proxy может использоваться вместо RealSubject
  • Реальный объект (Real Subject) - объект, доступ к которому ограничивается или откладывается.
  • Заместитель (Proxy) - суррогатный объект, который выступает в роли заместителя для реального объекта.
  • Клиент (Client) - объект, который использует заместитель для работы с реальным объектом.

Следствия от использования шаблона: Использование паттерна Заместитель может привести к следующим результатам:

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

Шаги реализации
1. Определите интерфейс, который бы сделал заместитель и оригинальный объект взаимозаменяемыми.
2. Создайте класс заместителя. Он должен содержать ссылку на сервисный объект. Чаще всего, сервисный объект создаётся самим заместителем. В редких случаях заместитель получает готовый сервисный объект от клиента через конструктор.
3. Реализуйте методы заместителя в зависимости от его предназначения. В большинстве случаев, проделав какую-то полезную работу, методы заместителя должны передать запрос сервисному объекту.
4. Подумайте о введении фабрики, которая решала бы, какой из объектов создавать — заместитель или реальный сервисный объект. Но, с другой стороны, эта логика может быть помещена в создающий метод самого заместителя.
5. Подумайте, не реализовать ли вам ленивую инициализацию сервисного объекта при первом обращении клиента к методам заместителя.

Преимущества
* Позволяет контролировать сервисный объект незаметно для клиента.
* Может работать, даже если сервисный объект ещё не создан.
* Может контролировать жизненный цикл служебного объекта.

Недостатки
* Усложняет код программы из-за введения дополнительных классов.
* Увеличивает время отклика от сервиса.

Какие типы прокси (“заместителей”) вы знаете?

  • Протоколирующий (Logging proxy) - используется для регистрации информации об операциях, выполняемых с реальным объектом, например, для отладки и анализа производительности.
  • Удалённый (Remote proxy) - используется для доступа к удаленному объекту через сеть, позволяет скрыть детали реализации удаленного объекта и обеспечить безопасный доступ к нему.
  • Виртуальный (Virtual proxy) - используется для отложенной(Ленивой) загрузки ресурсоемких объектов, например, изображений или больших файлов, для ускорения работы приложения и экономии ресурсов.
  • Copy-on-write proxy - используется для оптимизации копирования объектов, когда копия создается только при изменении оригинала.
  • Защищающий (Protection proxy) - используется для ограничения доступа к объекту и контроля его использования, например, для установки прав доступа или ограничения количества экземпляров.
  • Кэширующий (Caching proxy) - используется для кэширования результатов выполнения операций, чтобы ускорить повторные запросы к объекту.
  • “Умная” ссылка (Smart reference proxy) - используется для добавления дополнительной функциональности ссылкам на объекты, например, для подсчета числа ссылок или автоматической очистки памяти.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Расскажите про паттерн Итератор (Iterator).

A

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

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

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

Имя: Итератор (Iterator)

Назначение: Шаблон проектирования Итератор используется для доступа к элементам коллекции последовательно, без раскрытия ее внутренней структуры. Он предоставляет единый интерфейс для обхода различных типов коллекций.

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

Способ решения: Шаблон Итератор определяет интерфейс Iterator, который объявляет методы для доступа к элементам коллекции. Кроме того, он определяет класс ConcreteIterator, который реализует этот интерфейс и обеспечивает конкретную реализацию доступа к элементам коллекции.

Участники:

  • Iterator: определяет интерфейс для доступа к элементам коллекции;
  • ConcreteIterator: реализует интерфейс Iterator и обеспечивает конкретную реализацию доступа к элементам коллекции;
  • Aggregate: определяет интерфейс для создания объекта-итератора;
  • ConcreteAggregate: реализует интерфейс Aggregate и возвращает экземпляр ConcreteIterator.

Следствия от использования шаблона:
* Упрощение работы с коллекциями;
* Уменьшение зависимости между клиентским кодом и коллекциями;
* Повышение безопасности работы с данными;
* Возможность обходить коллекции различных типов, используя единый интерфейс;
* Увеличение гибкости и переносимости кода.

Шаги реализации
1. Создайте общий интерфейс итераторов. Обязательный минимум — это операция получения следующего элемента коллекции. Но для удобства можно предусмотреть и другое. Например, методы для получения предыдущего элемента, текущей позиции, проверки окончания обхода и прочие.
2. Создайте интерфейс коллекции и опишите в нём метод получения итератора. Важно, чтобы сигнатура метода возвращала общий интерфейс итераторов, а не один из конкретных итераторов.
3. Создайте классы конкретных итераторов для тех коллекций, которые нужно обходить с помощью паттерна. Итератор должен быть привязан только к одному объекту коллекции. Обычно эта связь устанавливается через конструктор.
4. Реализуйте методы получения итератора в конкретных классах коллекций. Они должны создавать новый итератор того класса, который способен работать с данным типом коллекции. Коллекция должна передавать ссылку на собственный объект в конструктор итератора.
5. В клиентском коде и в классах коллекций не должно остаться кода обхода элементов. Клиент должен получать новый итератор из объекта коллекции каждый раз, когда ему нужно перебрать её элементы.

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Расскажите про паттерн Шаблонный метод (Template Method).

A

Шаблонный Метод это поведенческий паттерн проектирования, который определяет скелет(шаблон) алгоритма, перекладывая ответственность за некоторые его шаги на подклассы. Паттерн позволяет подклассам переопределять шаги алгоритма, не меняя его общей структуры.

Паттерн предлагает разбить алгоритм на последовательность шагов, описать эти шаги в отдельных методах и вызывать их в одном шаблонном методе друг за другом.
Для описания шагов используется абстрактный класс. Общие шаги можно будет описать прямо в абстрактном класе. Это позволит подклассам переопределять некоторые шаги алгоритма, оставляя без изменений его структуру и остальные шаги, которые для этого подкласса не так важны.

Шаблонный метод (Template Method) - это поведенческий паттерн проектирования, который определяет скелет алгоритма, перекладывая некоторые шаги на подклассы. Шаблонный метод позволяет подклассам переопределить определенные шаги алгоритма, не меняя структуры алгоритма в целом.

Имя: Шаблонный метод (Template Method)
Назначение: Определение основных шагов алгоритма, но позволяет подклассам переопределить некоторые шаги этого алгоритма без изменения его структуры в целом.
Задача: Реализация повторяющихся операций с использованием общего алгоритма, но с различными реализациями некоторых шагов алгоритма в каждом подклассе.
Способ решения: Шаблонный метод предлагает определить скелет алгоритма в абстрактном классе, который содержит абстрактные методы, которые должны быть реализованы в подклассах. Конкретные реализации шагов алгоритма перекладываются на подклассы.
Участники:
Абстрактный класс, конкретные классы (подклассы).
Следствия: Шаблонный метод позволяет избежать дублирования кода, упрощает поддержку кода и обеспечивает гибкость и расширяемость системы.

Пример использования шаблонного метода может быть создание игры. В абстрактном классе определяется основной игровой цикл, включающий в себя инициализацию, обновление, отрисовку и окончание игры. Подклассы могут переопределить некоторые шаги этого цикла, такие как отрисовку или обновление объектов, чтобы создать различные виды игр. Таким образом, можно создавать новые игры, используя общий алгоритм игрового цикла, но с различными реализациями для каждой игры.

Шаги реализации
1. Изучите алгоритм и подумайте, можно ли его разбить на шаги. Прикиньте, какие шаги будут стандартными для всех вариаций алгоритма, а какие — изменяющимися.
2. Создайте абстрактный базовый класс. Определите в нём шаблонный метод. Этот метод должен состоять из вызовов шагов алгоритма. Имеет смысл сделать шаблонный метод финальным, чтобы подклассы не могли переопределить его (если ваш язык программирования это позволяет).
3. Добавьте в абстрактный класс методы для каждого из шагов алгоритма. Вы можете сделать эти методы абстрактными или добавить какую-то реализацию по умолчанию. В первом случае все подклассы должны будут реализовать эти методы, а во втором — только если реализация шага в подклассе отличается от стандартной версии.
4. Подумайте о введении в алгоритм хуков. Чаще всего, хуки располагают между основными шагами алгоритма, а также до и после всех шагов.
5. Создайте конкретные классы, унаследовав их от абстрактного класса. Реализуйте в них все недостающие шаги и хуки.

Преимущества
* Облегчает повторное использование кода.

Недостатки
* Вы жёстко ограничены скелетом существующего алгоритма.
* Вы можете нарушить принцип подстановки Барбары Лисков, изменяя базовое поведение одного из шагов алгоритма через подкласс.
* С ростом количества шагов шаблонный метод становится слишком сложно поддерживать.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Расскажите про паттерн Цепочка обязанностей (Chain of Responsibility).

A

Цепочка обязанностей — это поведенческий паттерн проектирования, который позволяет передавать запросы последовательно по цепочке обработчиков. Каждый последующий обработчик решает, может ли он обработать запрос сам и стоит ли передавать запрос дальше по цепи.
Базируется на том, чтобы превратить каждую проверку в отдельный класс с единственным методом выполнения. Данные запроса, над которым происходит проверка, будут передаваться в метод как аргументы.

Каждый из методов будет иметь ссылку на следующий метод-обработчик, что образует цепь.

В паттерне “Цепочка обязанностей” каждый обработчик решает, может ли он обработать запрос, и передает его следующему обработчику только в том случае, если он не может обработать запрос самостоятельно.

Имя: Цепочка обязанностей (Chain of Responsibility)

Назначение:

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

Задача:

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

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

Шаблон Цепочка обязанностей основан на идее организации объектов-обработчиков в виде цепочки, где каждый объект имеет ссылку на следующий объект в цепочке. При поступлении запроса на обработку от отправителя, первый объект в цепочке пытается обработать запрос, если он не может обработать запрос, то передает его следующему объекту в цепочке. Этот процесс продолжается до тех пор, пока запрос не будет обработан или пока цепочка не закончится.

Участники:

  • Интерфейс Handler, который определяет метод для обработки запросов и устанавливает ссылку на следующий объект в цепочке.
  • Конкретные классы, реализующие интерфейс Handler и определяющие свой способ обработки запросов.
  • Клиент, который создает цепочку объектов-обработчиков и отправляет запрос на обработку первому объекту в цепочке.

Следствия:

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

Шаги реализации

1.Создайте интерфейс обработчика и опишите в нём основной метод обработки.
Продумайте, в каком виде клиент должен передавать данные запроса в обработчик. Самый гибкий способ — превратить данные запроса в объект и передавать его целиком через параметры метода обработчика.

2.Имеет смысл создать абстрактный базовый класс обработчиков, чтобы не дублировать реализацию метода получения следующего обработчика во всех конкретных обработчиках.
Добавьте в базовый обработчик поле для хранения ссылки на следующий объект цепочки. Устанавливайте начальное значение этого поля через конструктор. Это сделает объекты обработчиков неизменяемыми. Но если программа предполагает динамическую перестройку цепочек, можете добавить и сеттер для поля.
Реализуйте базовый метод обработки так, чтобы он перенаправлял запрос следующему объекту, проверив его наличие. Это позволит полностью скрыть поле-ссылку от подклассов, дав им возможность передавать запросы дальше по цепи, обращаясь к родительской реализации метода.

3.Один за другим создайте классы конкретных обработчиков и реализуйте в них методы обработки запросов. При получении запроса каждый обработчик должен решить:
* Может ли он обработать запрос или нет?
* Следует ли передать запрос следующему обработчику или нет?

4.Клиент может собирать цепочку обработчиков самостоятельно, опираясь на свою бизнес-логику, либо получать уже готовые цепочки извне. В последнем случае цепочки собираются фабричными объектами, опираясь на конфигурацию приложения или параметры окружения.

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

6.Клиент должен знать о динамической природе цепочки и быть готов к таким случаям:
* Цепочка может состоять из единственного объекта.
* Запросы могут не достигать конца цепи.
* Запросы могут достигать конца, оставаясь необработанными.

Преимущества
* Уменьшает зависимость между клиентом и обработчиками.
* Реализует принцип единственной обязанности.
* Реализует принцип открытости/закрытости.
Недостатки
* Запрос может остаться никем не обработанным.

17
Q

Расскажите про Паттерн Стратегия

A

Паттерн “Стратегия” определяет семейство алгоритмов, инкапсулируя каждый алгоритм в отдельный класс. Позволяет менять алгоритм поведения вне зависимости от классов, которые его используют.

Имя: Стратегия (Strategy)

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

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

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

Участники:

  • Контекст (Context) - объект, который использует стратегии для выполнения определенной задачи. Контекст хранит ссылку на текущую стратегию и вызывает ее методы во время выполнения программы.
  • Абстрактная стратегия (Abstract Strategy) - абстрактный класс или интерфейс, определяющий общие методы для всех конкретных стратегий. Он может содержать некоторую реализацию, общую для всех стратегий.
  • Конкретные стратегии (Concrete Strategies) - классы, которые реализуют методы абстрактной стратегии. Каждый класс реализует альтернативный способ выполнения задачи.

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

Применимость
Когда вам нужно использовать разные вариации какого-то алгоритма внутри одного объекта.
Стратегия позволяет варьировать поведение объекта во время выполнения программы, подставляя в него различные объекты-поведения (например, отличающиеся балансом скорости и потребления ресурсов).

Когда у вас есть множество похожих классов, отличающихся только некоторым поведением.
Стратегия позволяет вынести отличающееся поведение в отдельную иерархию классов, а затем свести первоначальные классы к одному, сделав поведение этого класса настраиваемым.

Когда вы не хотите обнажать детали реализации алгоритмов для других классов.
Стратегия позволяет изолировать код, данные и зависимости алгоритмов от других объектов, скрыв эти детали внутри классов-стратегий.

Когда различные вариации алгоритмов реализованы в виде развесистого условного оператора. Каждая ветка такого оператора представляет собой вариацию алгоритма.
Стратегия помещает каждую лапу такого оператора в отдельный класс-стратегию. Затем контекст получает определённый объект-стратегию от клиента и делегирует ему работу. Если вдруг понадобится сменить алгоритм, в контекст можно подать другую стратегию.

Шаги реализации
1. Определите алгоритм, который подвержен частым изменениям. Также подойдёт алгоритм, имеющий несколько вариаций, которые выбираются во время выполнения программы.
2. Создайте интерфейс стратегий, описывающий этот алгоритм. Он должен быть общим для всех вариантов алгоритма.
3. Поместите вариации алгоритма в собственные классы, которые реализуют этот интерфейс
4. В классе контекста создайте поле для хранения ссылки на текущий объект-стратегию, а также метод для её изменения. Убедитесь в том, что контекст работает с этим объектом только через общий интерфейс стратегий.
5. Клиенты контекста должны подавать в него соответствующий объект-стратегию, когда хотят, чтобы контекст вёл себя определённым образом.

Преимущества
* Горячая замена алгоритмов на лету.
* Изолирует код и данные алгоритмов от остальных классов.
* Уход от наследования к делегированию.
* Реализует принцип открытости/закрытости.

Недостатки
* Усложняет программу за счёт дополнительных классов.
* Клиент должен знать, в чём состоит разница между стратегиями, чтобы выбрать подходящую.

18
Q

Расскажите про Паттерн Наблюдатель

A

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

Имя: Наблюдатель (Observer)

Назначение: Шаблон проектирования, который позволяет устанавливать отношение “один ко многим” между объектами таким образом, что при изменении состояния одного объекта все связанные с ним объекты уведомляются об этом и автоматически обновляются.

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

Способ решения: В шаблоне Наблюдатель определяются две основные роли: наблюдатель и субъект. Субъект содержит список наблюдателей и предоставляет методы для добавления, удаления и уведомления наблюдателей о изменении своего состояния. Наблюдатели реализуют интерфейс, который определяет метод, вызываемый при уведомлении об изменении состояния субъекта.

Участники:

  • Субъект: объект, чье состояние изменяется и которое нужно отслеживать.
  • Наблюдатель: объект, который получает уведомление об изменении состояния субъекта и реагирует на это изменение.

Следствия от использования шаблона:
* Уменьшение связанности между объектами, что позволяет легко добавлять и удалять объекты-наблюдатели без изменения исходного объекта.
* Возможность реализации сложной логики в уведомлении наблюдателей без изменения исходного объекта.
* Расширяемость и гибкость кода.

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

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

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

  • Издатели ведут динамические списки. Все наблюдатели могут подписываться или отписываться от получения оповещений прямо во время выполнения программы.

Шаги реализации
1. Разбейте вашу функциональность на две части: независимое ядро и опциональные зависимые части. Независимое ядро станет издателем. Зависимые части станут подписчиками.
2. Создайте интерфейс подписчиков. Обычно в нём достаточно определить единственный метод оповещения.
3. Создайте интерфейс издателей и опишите в нём операции управления подпиской. Помните, что издатель должен работать только с общим интерфейсом подписчиков.
4. Вам нужно решить, куда поместить код ведения подписки, ведь он обычно бывает одинаков для всех типов издателей. Самый очевидный способ — вынести этот код в промежуточный абстрактный класс, от которого будут наследоваться все издатели.
Но если вы интегрируете паттерн в существующие классы, то создать новый базовый класс может быть затруднительно. В этом случае вы можете поместить логику подписки во вспомогательный объект и делегировать ему работу из издателей.
5. Создайте классы конкретных издателей. Реализуйте их так, чтобы после каждого изменения состояния они отправляли оповещения всем своим подписчикам.
6. Реализуйте метод оповещения в конкретных подписчиках. Не забудьте предусмотреть параметры, через которые издатель мог бы отправлять какие-то данные, связанные с происшедшим событием.
Возможен и другой вариант, когда подписчик, получив оповещение, сам возьмёт из объекта издателя нужные данные. Но в этом случае вы будете вынуждены привязать класс подписчика к конкретному классу издателя.
1. Клиент должен создавать необходимое количество объектов подписчиков и подписывать их у издателей.

Преимущества
* Издатели не зависят от конкретных классов подписчиков и наоборот.
* Вы можете подписывать и отписывать получателей на лету.
* Реализует принцип открытости/закрытости.

Недостатки
* Подписчики оповещаются в случайном порядке.

19
Q

Расскажите про Паттерн Фасад

A

Фасад — это структурный паттерн проектирования, который предоставляет простой интерфейс к сложной системе классов, библиотеке или фреймворку.

Шаблон Фасад (Facade) - это структурный шаблон проектирования, который позволяет предоставить унифицированный интерфейс для группы интерфейсов в системе. Это позволяет скрыть сложность системы и упростить взаимодействие клиента с ней.

Имя: Фасад (Facade)

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

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

Способ решения, предлагаемый в шаблоне: Шаблон Фасад предлагает создание класса-фасада, который скрывает сложность системы и предоставляет клиенту унифицированный интерфейс для работы с ней. Класс-фасад выполняет необходимые операции, связанные с взаимодействием с другими классами в системе, и предоставляет клиенту только необходимые функции.

Участники: В шаблоне Фасад участвуют следующие сущности:

  • Клиент: пользователь, который использует систему.
  • Класс-фасад: класс, который предоставляет унифицированный интерфейс для работы с системой.
  • Классы-подсистемы: классы, которые представляют отдельные компоненты системы и используются классом-фасадом для выполнения необходимых операций.

Следствия от использования шаблона: Использование шаблона Фасад может привести к следующим результатам:
* Упрощение взаимодействия клиента с системой.
* Уменьшение связанности между компонентами системы.
* Улучшение поддерживаемости и расширяемости системы за счет возможности изменять внутреннюю реализацию компонентов без влияния на клиентский код.
* Сокрытие сложности системы от клиента, что позволяет увеличить уровень безопасности и уменьшить количество ошибок при использовании системы.

Применимость

Когда вам нужно представить простой или урезанный интерфейс к сложной подсистеме.

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

Когда вы хотите разложить подсистему на отдельные слои.

  • Используйте фасады для определения точек входа на каждый уровень подсистемы. Если подсистемы зависят друг от друга, то зависимость можно упростить, разрешив подсистемам обмениваться информацией только через фасады.
  • Например, возьмём ту же сложную систему видеоконвертации. Вы хотите разбить её на слои работы с аудио и видео. Для каждой из этих частей можно попытаться создать фасад и заставить классы аудио и видео обработки общаться друг с другом через эти фасады, а не напрямую.

Шаги реализации
1. Определите, можно ли создать более простой интерфейс, чем тот, который предоставляет сложная подсистема. Вы на правильном пути, если этот интерфейс избавит клиента от необходимости знать о подробностях подсистемы.
2. Создайте класс фасада, реализующий этот интерфейс. Он должен переадресовывать вызовы клиента нужным объектам подсистемы. Фасад должен будет позаботиться о том, чтобы правильно инициализировать объекты подсистемы.
3. Вы получите максимум пользы, если клиент будет работать только с фасадом. В этом случае изменения в подсистеме будут затрагивать только код фасада, а клиентский код останется рабочим.
4. Если ответственность фасада начинает размываться, подумайте о введении дополнительных фасадов.

Преимущества и недостатки
++++++++++++++++++++++++++++++++++
Изолирует клиентов от компонентов сложной подсистемы.

` ——————————————–`

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

20
Q

Какие паттерны используются в Spring Framework?

A

Inversion of Control (IoC) - паттерн, который делегирует контроль над созданием и управлением объектов контейнеру. Spring Framework предоставляет свой собственный контейнер IoC - ApplicationContext, который управляет жизненным циклом объектов и их зависимостей.

Dependency Injection (DI) - паттерн, который позволяет внедрять зависимости объектов во время выполнения, что облегчает тестирование и уменьшает связность. Spring Framework предоставляет множество способов внедрения зависимостей, включая конструкторы, сеттеры и аннотации.

Фабричный метод (Factory Method) - паттерн, который определяет интерфейс для создания объектов, но позволяет подклассам решать, какие классы конкретно создавать. Spring Framework использует фабричный метод в качестве механизма создания объектов в IoC-контейнере.

Singleton - паттерн, который гарантирует, что в приложении будет только один экземпляр класса. Spring Framework использует singleton-объекты по умолчанию в IoC-контейнере, что обеспечивает глобальный доступ к экземпляру класса.

Prototype

Шаблон проектирования фасад (Facade) - паттерн, который предоставляет удобный интерфейс для более сложной системы. Spring Framework использует шаблон проектирования фасад для облегчения использования более сложных компонентов, таких как базы данных и ORM.

Шаблон проектирования стратегия (Strategy) - паттерн, который определяет семейство алгоритмов и инкапсулирует каждый из них, позволяя им быть взаимозаменяемыми. Spring Framework использует шаблон проектирования стратегия для реализации различных стратегий обработки запросов.

Аспектно-ориентированное программирование (AOP) - паттерн, который позволяет выносить общие функции приложения в отдельные модули, называемые аспектами. Spring Framework поддерживает AOP, что позволяет реализовывать такие функции, как логирование, транзакции и безопасность, с помощью аспектов.

Шаблон проектирования наблюдатель (Observer) - паттерн, который определяет зависимость “один-ко-многим” между объектами, таким образом, что при изменении состояния одного объекта все зависимые от него объекты оповещаются и обновляются автоматически. Spring Framework использует этот паттерн в механизме обработки событий.

Шаблон проектирования шаблонный метод (Template Method) - паттерн, который определяет каркас алгоритма, но позволяет подклассам переопределять некоторые шаги этого алгоритма. Spring Framework использует этот паттерн в абстрактных классах и интерфейсах, которые определяют общие методы для конкретных реализаций.

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

Шаблон проектирования фабрика (Factory) - паттерн, который определяет интерфейс для создания объектов, но делегирует создание подклассам. Spring Framework использует этот паттерн для создания объектов в IoC-контейнере.

Шаблон проектирования команда (Command) - паттерн, который инкапсулирует запрос как объект, позволяя настраивать параметры вызова и хранить историю вызовов. Spring Framework использует этот паттерн в механизме обработки запросов MVC, где каждый запрос представлен объектом команды.

Шаблон проектирования состояние (State) - паттерн, который позволяет объекту менять свое поведение в зависимости от своего внутреннего состояния. Spring Framework использует этот паттерн в механизме обработки состояний (stateful beans), где состояние объекта сохраняется между вызовами методов.

Шаблон проектирования адаптер (Adapter) - позволяет объектам работать вместе, несмотря на несовместимость их интерфейсов. Spring Framework использует этот паттерн, например, в Spring Web и Spring MVC.

Шаблон проектирования декоратор (Decorator) - позволяет добавлять новые функциональные возможности существующим объектам без изменения их кода. Spring Framework использует этот паттерн, например, при использовании аннотаций @Transactional и @Secured для добавления транзакционности и безопасности в существующие методы.

21
Q

Какие паттерны используются в Hibernate?

A

Object-relational mapping (ORM) - Hibernate использует ORM для преобразования данных из реляционной базы данных в объекты, которые можно использовать в объектно-ориентированном программировании.

Data Access Object (DAO) - Hibernate использует DAO для предоставления абстракции для доступа к данным, скрывая детали работы с базой данных.

Factory - Hibernate использует Factory для создания объектов без явного вызова конструктора.

Unit of Work - Hibernate использует Unit of Work для отслеживания изменений объектов и сохранения их в базе данных в одной транзакции.

Identity Map - Hibernate использует Identity Map для хранения объектов, чтобы избежать повторного получения одного и того же объекта из базы данных.

Lazy Loading - Hibernate использует Lazy Loading для загрузки объектов из базы данных только при необходимости, что может повысить производительность при работе с большими объемами данных.

Proxy - Hibernate использует Proxy для создания объектов-заместителей для доступа к объекту, который может быть загружен из базы данных при необходимости.

Template Method - Hibernate использует Template Method для упрощения работы с базой данных через предоставление шаблонных методов для выполнения операций (например, сохранение, обновление, удаление объектов).

Domain Model - это объектная модель предметной области, которая включает в себя как поведение, так и данные. Это означает, что модель содержит объекты, которые представляют сущности в предметной области, и методы, которые позволяют этим объектам взаимодействовать друг с другом. Domain Model служит основой для работы с базой данных и может быть использована вместе с ORM, чтобы упростить манипуляцию данными.

Data Mapper - это слой мапперов (Mappers), который передает данные между объектами и базой данных, сохраняя их независимыми друг от друга и себя. Это означает, что Data Mapper обеспечивает отделение между объектной моделью предметной области и базой данных. Он позволяет сохранять объекты в базу данных и извлекать их оттуда, не нарушая инкапсуляцию и независимость объектов. Data Mapper используется для сопоставления (mapping) данных между объектами и таблицами в базе данных, а также для обеспечения согласованности данных.

22
Q

В чём отличия и сходства паттернов Adapter, Decorator, Wrapper и Proxy?

A

Заместитель (proxy) оборачивает некоторый класс и предоставляет такой же интерфейс. Цель – “притвориться” оригинальным классом и скрыть от клиента детали. Типичные примеры использования – ленивая инициализация оборачиваемого класса или оборачивание вызовов стороннего сервиса.
Proxy - это заместитель (например, как банковский чек замещает пачку наличности). Это дублер, который временно замещает оригинал.
Прокси - это объект-заместитель, который контролирует доступ к другому объекту. Он может использоваться, например, для ограничения доступа к ресурсам или для ленивой загрузки данных. Кроме того, прокси может выполнять дополнительную логику, такую как кэширование результатов или обработку ошибок.

Декоратор также оборачивает некоторый класс и предоставляет такой же или расширенный интерфейс. Иногда декоратор называют “умным заместителем” (smart proxy). Т.е. декоратор может притворяться оригинальным классом и при этом расширять его функциональность. Пример: у вас есть заместитель, который прячет вызовы к стороннему сервису. Можно создать декоратор, который будет оборачивать и кэшировать результаты вызовов. Другой пример: нужно расширить функциональность оригинального класса, но он закрыт для наследования. Создается декоратор, который расширяет интерфейс оригинального класса.
Декоратор (Wraper) позволяет создать цепочку оберток, и каждая обертка добавляет что-то к исходному объекту. Обогащает его функционал. Было побайтовое чтение, раз и добавили оберткой буферизацию, а потом еще что-нибудь… и т.д.
Декоратор - это объект-обертка, который добавляет дополнительное поведение к другому объекту без изменения его интерфейса. Декоратор оборачивает оригинальный объект и дополняет его функциональностью, причем это дополнение может быть выполнено динамически.

Адаптер также оборачивает некоторый класс, но при этом предоставляет другой интерфейс. Т.е. используется в случаях, когда есть класс с нужными данными и поведением, но с неподходящим интерфейсом.
Адаптер - посредник, переходник. Например, конвертировать данные одного формата в другой формат, чтобы две независимые библиотеки могли договориться друг с другом (например, XML и JSON).
Адаптер - это объект, который преобразует интерфейс одного объекта в интерфейс другого объекта. Адаптер может использоваться для обеспечения взаимодействия объектов с несовместимыми интерфейсами или для адаптации старых объектов к новым требованиям.

Итого:
Что делает с интерфейсом | Что делает с функциональностью
Заместитель | Не изменяет | Не изменяет |
----------------------------------------------------------
| Декоратор | Не изменяет/расширяет | Расширяет |
---------------------------------------------------------
| Адаптер | Изменяет | Не изменяет |
Что касается того, как они выглядят на уровне кода. Реализации, само собой, могут варьироваться, поэтому чтобы определить, что есть что, пользуйтесь следующими шагами:

  • Определите оригинальный объект/класс.
  • Посмотрите, какой интерфейс предоставляет обертка.
  • Посмотрите, какую функциональность предоставляет обертка.