Образцы проектирования

Содержание

Слайд 2

Образец проектирования

Образец (шаблон) проектирования – повторно используемое решение типичной проблемы проектирования.
Состоит из*:
Имени
(Абстрактной)

Образец проектирования Образец (шаблон) проектирования – повторно используемое решение типичной проблемы проектирования.
формулировки задачи, для решения которой применим шаблон
(Абстрактного) решения – описание элементов дизайна, их поведения и отношений между ними
Результаты – последствия применения образца, побочные эффекты, в т.ч. нежелательные
*Э. Гамма и др., Приемы объектно-ориентированного проектирования: шаблоны проектирования

Слайд 3

Классификация образцов

Структурные – решают задачи, связанные с отношением между классами (или другими

Классификация образцов Структурные – решают задачи, связанные с отношением между классами (или
сущностями)
Поведенческие – решают задачи поведения классов
Порождающие – решают задачи создания экземпляров классов и их инициализации

Слайд 4

Базовые структурные образцы

Abstract Server
Adapter
Proxy

Базовые структурные образцы Abstract Server Adapter Proxy

Слайд 5

Abstract Server: пример задачи

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

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

Слайд 6

Abstract Server: пример решения

Решение: поставить выключатель в зависимость от абстракции (применить DIP)

Abstract Server: пример решения Решение: поставить выключатель в зависимость от абстракции (применить DIP)

Слайд 7

Abstract Server: образец

Задача: исключить зависимость класса-клиента от реализации класса-сервера
Решение: использовать абстракцию (абстрактный

Abstract Server: образец Задача: исключить зависимость класса-клиента от реализации класса-сервера Решение: использовать
класс или интерфейс) вместо сервера
Результаты:
повторно используемый клиент
соблюдение DIP

Слайд 8

Abstract Server: замечания

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

Abstract Server: замечания Практически любой класс, предоставляющий функциональность наружу пакета рассматривается как

=> использование такого класса напрямую нарушает DIP
=> вся функциональность пакета должна быть абстрагирована с помощью применения Abstract Server, либо других паттернов с аналогичных эффектов (напр. Facade)

Слайд 9

Adapter: пример задачи

Проблема: использовать выключатель для прибора с несовместимой по форме (но

Adapter: пример задачи Проблема: использовать выключатель для прибора с несовместимой по форме
совместимой по напряжению) розеткой

Слайд 10

Adapter: пример решения

Решение: использовать переходник из одной розетки в другую

Adapter: пример решения Решение: использовать переходник из одной розетки в другую

Слайд 11

Adapter: образец

Задача: адаптировать класс для использования через интерфейс, который класс изначально не реализует
Решение:

Adapter: образец Задача: адаптировать класс для использования через интерфейс, который класс изначально
использовать класс-адаптер, реализующий требуемый интерфейс и делегирующий их реализацию адаптируемому классу

Слайд 12

Proxy: пример задачи

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

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

Слайд 13

Proxy: пример решения

Решение: вместо настоящего изображения, используется заместитель, который загружает изображение только

Proxy: пример решения Решение: вместо настоящего изображения, используется заместитель, который загружает изображение
в случае его отображения.

Слайд 14

Proxy: образец

Задача: обеспечить контроль доступа к объектам класса: авторизацию, загрузку, удаленное обращение

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

Слайд 15

Области применения Proxy

Доступ к удаленному объекту
Доступ к «тяжелому» объекту: отложенная загрузка, выгрузка

Области применения Proxy Доступ к удаленному объекту Доступ к «тяжелому» объекту: отложенная
из памяти
Мемоизация вычислений
Авторизация доступа
«Умные» указатели

Слайд 16

Жизненный цикл объекта

object: SomeClass

Объект создан

Объект инициализирован

Первое использование объекта

Последнее использование объекта

Объект деинициализирован

Объект уничтожен

Получение ссылки

Жизненный цикл объекта object: SomeClass Объект создан Объект инициализирован Первое использование объекта
на объект

Выход из области видимости

Слайд 17

Проблемы контроля жизненного цикла объектов

Контроль жизненного цикла – cross-cutting concern
Проблемы:
Вызов конструктора невозможно

Проблемы контроля жизненного цикла объектов Контроль жизненного цикла – cross-cutting concern Проблемы:
сделать виртуальным в классической объектной модели, т.е. Abstract Server не применим при создании.
Для создания объекта могут требоваться данные, которыми создающий объект обладать не должен (чтобы не нарушать ORR)
Явное удаление объекта может нарушать ORR
Неявное удаление объекта (через сборщик мусора) не гарантирует освобождения ресурсов.
Потенциальное нарушение LoD при использовании одного и того же объекта в разных частях объектной модели
Использование объекта до инициализации
Использование объекта после деинициализации

Слайд 18

Порождающие образцы

RAII
Lazy Initialization
Singleton
Abstract Factory
Prototype
Builder
Dependency Injection

Порождающие образцы RAII Lazy Initialization Singleton Abstract Factory Prototype Builder Dependency Injection

Слайд 19

Resource Acquisition Is Initialization (RAII)

Пример задачи: необходимо обеспечить простую и эффективную с

Resource Acquisition Is Initialization (RAII) Пример задачи: необходимо обеспечить простую и эффективную
точки зрения блокирования ресурсов работу с файловыми потоками.
Пример решения (С++):
объявляем класс файлового потока;
объявляем конструктор, открывающий поток;
объявляем деструктор, закрывающий поток;
объявляем методы для чтения/записи;
используем, как стековый объект;
Для захвата ресурса достаточно создать объект-поток. Объект будет гарантированно закрыт в момент выхода объекта из области видимости (в т.ч. в связи с исключительной ситуации)

Слайд 20

Resource Acquisition Is Initialization (RAII)

object: SomeClass

Объект создан

Объект инициализирован

Первое использование объекта

Последнее использование объекта

Объект деинициализирован

Объект

Resource Acquisition Is Initialization (RAII) object: SomeClass Объект создан Объект инициализирован Первое
уничтожен

Получение ссылки на объект

Выход из области видимости

Атомарные операции

Слайд 21

RAII: конструирование
Конструирование (захват ресурсов) должно производиться атомарным вызовом (конструктора или порождающей функции).

RAII: конструирование Конструирование (захват ресурсов) должно производиться атомарным вызовом (конструктора или порождающей функции).

Слайд 22

RAII: уничтожение
С++: для стековых объектов в момент выхода переменной из области видимости
Языки

RAII: уничтожение С++: для стековых объектов в момент выхода переменной из области
с динамической сборкой мусора: момент уничтожения объекта не определен, требуется явная деинициализация

Слайд 23

RAII: Java

FileOutputStream out = null;
try{
out = new FileOutputStream (outFile);
//…
}
finally{
out.close();
}

RAII: Java FileOutputStream out = null; try{ out = new FileOutputStream (outFile);

Слайд 24

RAII: анализ

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

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

Слайд 25

Отложенная инициализация (Lazy Initialization)

Пример задачи: необходимо реализовать класс изображений, загружаемых с файловой

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

Слайд 26

Отложенная инициализация: образец

object: SomeClass

Объект создан

Получены данные инициализации

Фактическая инициализация, первое использование объекта

Получение ссылки на

Отложенная инициализация: образец object: SomeClass Объект создан Получены данные инициализации Фактическая инициализация,
объект


Слайд 27

Отложенная инициализация: анализ

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

Отложенная инициализация: анализ Преимущества: Оптимизирует вычисления, избавляясь от инициализации ненужных объектов. Оптимизирует
захватывая их непосредственно перед фактическим использованием.
Недостатки:
Теряется контроль над использованием вычислительных ресурсов (плохо для систем реального времени).
Не контролируется порядок захвата ресурсов => мертвые и живые блокировки.

Слайд 28

Лирическое отступление: отложенное исполнение

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

Лирическое отступление: отложенное исполнение Отложенные вычисления: вычисления происходят не в момент вызова,
а, либо в момент затребования результата, либо асинхронно в произвольный момент времени.
Необходимое условие: чистота отложенного вызова
Распространенные примеры:
отложенная инициализация
copy-on-write
мелкозернистые вычисления
бесконечные структуры данных

Слайд 29

Понятие чистой функции

Чистая функция (referential transparent) – функция, значение которой полностью определяется

Понятие чистой функции Чистая функция (referential transparent) – функция, значение которой полностью
ее параметрами, и функция не имеет побочных эффектов, (т.е. никаких дополнительных эффектов кроме возврата значения)
Использование чистых функций повышает логическую безопасность программы, следует использовать

Слайд 30

Singleton

Задача: обеспечить создание ровно одного экземпляра класса.
Решение:
public class Singleton(){
private static Singleton

Singleton Задача: обеспечить создание ровно одного экземпляра класса. Решение: public class Singleton(){
instance = null;
private Singleton(){…}
public static Singleton getInstance(){
if (instance == null) instance = new Singleton();
return instance;
}
}

Слайд 31

Singleton: анализ

Применение:
глобально-доступный инструментарий, который не может быть представлен обычными функциями (например,

Singleton: анализ Применение: глобально-доступный инструментарий, который не может быть представлен обычными функциями
использует дополнительные конфигурационные параметры)
Как правило, с точки зрения бизнес-логики синглтон не хранит какого-либо состояния.
Отличия от глобальной переменной:
Может участвовать в полиморфизме
Инициализируется только при реальном использовании
Интерфейс не содержит предположений относительно количества экземпляров

Слайд 32

Abstract Factory: пример задачи

Клиент не должен зависеть от реализации виджетов.
Клиент может использовать

Abstract Factory: пример задачи Клиент не должен зависеть от реализации виджетов. Клиент
их через базовые платформенно-независимые классы.
Как дать клиенту возможность инстанцировать эти классы?

Слайд 33

Abstract Factory: пример решения

Abstract Factory: пример решения

Слайд 34

Задача: обеспечить «полиморфный» конструктор
Решение: конструирование выполняется с помощью объекта дополнительного полиморфного класса
Последствия:
Фабрика имеет право

Задача: обеспечить «полиморфный» конструктор Решение: конструирование выполняется с помощью объекта дополнительного полиморфного
выбросить исключение (в отличие от конструктора)
Проблема инстанцирования фабрики (кто побреет брадобрея?)

Abstract Factory: образец

Слайд 35

Prototype

Пример задачи: см. «Abstract Factory»
Решение: объекты создаются как клоны объектов-прототипов

Prototype Пример задачи: см. «Abstract Factory» Решение: объекты создаются как клоны объектов-прототипов

Слайд 36

Prototype: анализ

Преимущества:
простой дизайн
прототип обладает свойствами класса, его можно применять для создания

Prototype: анализ Преимущества: простой дизайн прототип обладает свойствами класса, его можно применять
динамических объектных моделей в статических языках
Недостатки:
лишние, «мусорные» объекты
В JavaScript прототипы полностью заменяют классы.

Слайд 37

Builder: задача
Необходимо сконструировать сложный объект (например HTML-документ), что невозможно сделать атомарным вызовом.

Builder: задача Необходимо сконструировать сложный объект (например HTML-документ), что невозможно сделать атомарным

При этом необходимо, чтобы при получении доступа к объекту он был консистентен.

Слайд 38

Builder: образец
Решение:
Клиент использует build*- методы для инициализации объекта. Далее, объект востребуется атомарно посредством getProduct
Результаты:
Совместимость с

Builder: образец Решение: Клиент использует build*- методы для инициализации объекта. Далее, объект
RAII

Слайд 39

Builder (GOF-вариант)
Задача:
Сконструировать сложный объект, причем алгоритм конструирования не должен зависеть от того, какой

Builder (GOF-вариант) Задача: Сконструировать сложный объект, причем алгоритм конструирования не должен зависеть
конкретно объект будет получен в результате

Слайд 40

IoC и жизненный цикл объекта
Garbage Collector: вместо явного уничтожения объект «забывается» и

IoC и жизненный цикл объекта Garbage Collector: вместо явного уничтожения объект «забывается»
далее обрабатывается некоторой внешней сущность (GC)
Можно ли то же самое сделать с конструированием объекта?

Слайд 41

Инициализация зависимостей без применения Dependency Injection
public interface ITool{ …}
public class Fork implements ITool{

Инициализация зависимостей без применения Dependency Injection public interface ITool{ …} public class
… }
//non-DI class
public class Person1{
ITool tool;
public Person(){
tool = new Fork(); //создаем вилку самостоятельно
}
}

Слайд 42

Тривиальный Dependency Injection (DI) на основе конструктора

//constructor-based DI class
public class Person2{
ITool

Тривиальный Dependency Injection (DI) на основе конструктора //constructor-based DI class public class
tool;
public Person(ITool tool){ //требуем некоторый инструмент
this.tool = tool;
}
}

public static void main(){
ITool tool = new Fork();
//выдаем инструмент (вилку) в пользование
Person2 person = new Person2(tool);
}

Слайд 43

Преимущества DI

Агрегирующие классы (т.е. те, для которых работает DI) не обязаны зависеть

Преимущества DI Агрегирующие классы (т.е. те, для которых работает DI) не обязаны
от конкретных классов включаемых объектов (соблюдается DIP)
Можно явно указать какие зависимости будут общими для нескольких агрегирующие классов. При этом агрегирующие классы могут об этом не знать.
Агрегирующие классы не зависят от «божественной» сущности, которая реализует DI

Слайд 44

Проблемы с тривиальным DI
DI реализует «божественная» сущность, зависящая от всей системы (нарушение

Проблемы с тривиальным DI DI реализует «божественная» сущность, зависящая от всей системы
ORR, LoD)
Явно позволяет реализовать только статическое связывание. Что делать, если инструмент сломался и его нужно заменить?

Слайд 45

DI на основе контейнера

Контейнер универсален и не зависит от конкретных классов реализации.

DI на основе контейнера Контейнер универсален и не зависит от конкретных классов
Зависимость устанавливается внешними конфигурационными файлами. Сам контейнер работает через интроспекцию (Java Reflection и т.д.)
Зависимости могут внедряться опосредовано через proxy. Это позволяет подменять зависимости в соответствии с контекстом (поток, сессия и т.д.)
Возможно конфигурировать жизненный цикл отдельных объектов (типично singleton, session, call)

Слайд 46

DI: Spring framework example

//container-based DI class
public class Person3 implements IPerson{
@Inject ITool

DI: Spring framework example //container-based DI class public class Person3 implements IPerson{
tool;
}
//applicationContext.xml



Слайд 47

Поведенческие образцы

Iterator
Observer
Immutable Object
Memento
Template method
Strategy
Command
Chain of responsibilities

Поведенческие образцы Iterator Observer Immutable Object Memento Template method Strategy Command Chain of responsibilities

Слайд 48

Iterator

Задача: имеется составной объект (список, дерево), необходимо обеспечить доступ к отдельным его

Iterator Задача: имеется составной объект (список, дерево), необходимо обеспечить доступ к отдельным
частям и перемещение между ними.
Решение: дополнительный класс, обеспечивающий:
доступ к текущему элементу
перемещение к следующему элементу
удаление элемента (опционально)
вставку элемента «после» (опционально)

Слайд 49

Observer

Задача: автоматически оповещать объектов-наблюдателей об изменении состояния наблюдаемого объекта.
Решение:

Observer Задача: автоматически оповещать объектов-наблюдателей об изменении состояния наблюдаемого объекта. Решение:

Слайд 50

Immutable Object
Неизменяемый объект: объект, получающий состояние при конструировании и не меняющий его.

Immutable Object Неизменяемый объект: объект, получающий состояние при конструировании и не меняющий

Изменение состояния моделируется заменой самого объекта

Слайд 51

Immutable Object: анализ

Преимущества:
является необходимым условием для кода без побочных эффектов;
существенно упрощает синхронизацию

Immutable Object: анализ Преимущества: является необходимым условием для кода без побочных эффектов;
потоков/процессов;
повышает логическую безопасность кода.
Недостатки:
накладные расходы на копирование объектов;
практически невозможно построить интерактивное приложение только на IO

Слайд 52

Memento

Задача: обеспечить сохранение текущего состояния объекта и его последующее восстановления (для передачи

Memento Задача: обеспечить сохранение текущего состояния объекта и его последующее восстановления (для
объекта по сети, операций отката и т.д.
Решение:

Слайд 53

Memento: анализ

Преимущества:
Обеспечивает сериализацию (маршалинг) объектов без привязки к конкретному формату/протоколу передачи.
Недостатки:
Затруднено применение

Memento: анализ Преимущества: Обеспечивает сериализацию (маршалинг) объектов без привязки к конкретному формату/протоколу
для сложных объектов с (например с циклическими внутренними зависимостями)

Слайд 54

Template Method

Задача: реализовать универсальный класс Thread
Решение:

Template Method Задача: реализовать универсальный класс Thread Решение:

Слайд 55

Template Method: образец

Template Method: образец

Слайд 56

Template Method: анализ

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

Template Method: анализ Преимущества: Позволяет реализовать универсальный абстрактный алгоритм, пропускающий некоторые детали
Детали реализуются классе-потомке.
Недостатки:
Обеспечивает только статическое связывание с деталями реализации. Класс, реализующий детали зависит от всего алгоритма (потенциальное нарушение DIP)

Слайд 57

Strategy

Задача: см. Template Method
Решение:

Strategy Задача: см. Template Method Решение:

Слайд 58

Strategy: образец

Strategy: образец

Слайд 59

Strategy: анализ

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

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

Слайд 60

Задача: интерфейс командной строки

все команды имеют вид command_name [args]
набор команд должен быть расширяем
добавление

Задача: интерфейс командной строки все команды имеют вид command_name [args] набор команд
новых команд не должно изменять ядро (т.е. должен соблюдаться OCP)

Слайд 61

Решение

Решение

Слайд 62

GeneralProcessor

class GeneralProcessor{
//…
public void executeCommand(Command command){
boolean isProcessed = false;
for (IProcessor

GeneralProcessor class GeneralProcessor{ //… public void executeCommand(Command command){ boolean isProcessed = false;
p: procs){
try{
p.executeCommand();
}
catch (UnknownCommand ex){
continue;
}
isProcessed = true;
break;
}
if (!isProcessed) throw new UnknownCommand ();
}
//…
}

Слайд 63

Использованные шаблоны
Strategy (2 раза)
Chain of Responsibilities
Command
Facade

Использованные шаблоны Strategy (2 раза) Chain of Responsibilities Command Facade

Слайд 64

Command-Query Separation (CQS)

CQS – принцип построения интерфейсов.
Каждый метод является либо командой, либо

Command-Query Separation (CQS) CQS – принцип построения интерфейсов. Каждый метод является либо
запросом но не тем и другим одновременно.
Команда – метод, изменяющий состояние объекта и не возвращающий никакого значения
Запрос – метод без побочных эффектов, возвращающий значение.
Имя файла: Образцы-проектирования.pptx
Количество просмотров: 138
Количество скачиваний: 0