236
УК 03.003.01-2011 Учебный курс. Обучение. Шаблоны ОО проектирования.

ук 03.003.01 2011

Embed Size (px)

Citation preview

Page 1: ук 03.003.01 2011

УК 03.003.01-2011 Учебный курс. Обучение.

Шаблоны ОО проектирования.

Page 2: ук 03.003.01 2011

Определение паттерна

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

• Кристофер Александр, 1977 для архитектуры

• Паттерн – это не готовый к использованию набор классов, а лишь описание способа решения конкретной задачи.

• Тригонометрическая подстановка для решения интеграла.

Page 3: ук 03.003.01 2011

Шаблон описания паттерна

• Название и классификация паттерна • Назначение • Имя синоним • Мотивация • Применимость • Структура • Участники • Отношения • Результаты • Реализация • Пример кода • Известные применения • Родственные паттерны

Page 4: ук 03.003.01 2011

Абстрактная фабрика

Категория: паттерн, порождающий объекты

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

Имя синоним: Kit (Инструментарий)

Page 5: ук 03.003.01 2011

Мотивация

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

• Имя класса в тексте программы – потенциальный источник нарушения принципа подстановки Лисков и открыто-замкнутого принципа

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

• Идеальный вариант – имя класса упоминается лишь один раз во всем тексте программы, что избежать проблемы Copy-Paste

Page 6: ук 03.003.01 2011

• AbstractProductA CreateProductA() – метод инкапсулирует в себе создание экземпляра ProductA, нам доступен лишь интерфейс базового класса. Такой подход удовлетворяет принципу подстановки Лисков.

• Как компоновать методы, создающие объекты?

• Есть классы сильно сцепленные между собой, а есть – независимые.

• Объединим методы, создающие сильно сцепленные объекты между собой в один класс (обобщенный принцип повторного использования, обобщенный принцип замкнутости)

Page 7: ук 03.003.01 2011

• Согласно принципу единственной ответственности каждый класс должен заниматься выполнением только одной операции.

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

Page 8: ук 03.003.01 2011

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

• необходимо обеспечить замкнутость относительно создания, компоновки и представления входящих в нее объектов (способ создания объекта скрыт за вызываемым методом);

• Необходимо обеспечить ограничение – взаимосвязанные объекты должны использоваться вместе (реализации File, Directory);

• Необходимо обеспечить конфигурирование одним из семейств классов (Работа через протокол Tcp, Udp);

• Необходимо раскрыть только интерфейсы, реализация должна быть закрыта.

Page 9: ук 03.003.01 2011

Структура

Page 10: ук 03.003.01 2011

Отношения

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

• Абстрактная фабрика делегирует создание объектов продуктов конкретной фабрике.

Page 11: ук 03.003.01 2011

Результат

• Стратегическая замкнутость:

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

• Замкнутость не обеспечивается для:

– Добавления новых видов продуктов.

• Побочные эффекты:

– Упрощает замену семейств продуктов;

– Гарантия сочетаемости продуктов.

Page 12: ук 03.003.01 2011

Вопросы реализации

• Фабрика как Singleton

• Создание продукта: – Фабричный метод

– Прототип

• Расширяемые фабрики – Использование сборок

– Распределенная фабрика (COM, процедура инициализация DLL)

Page 13: ук 03.003.01 2011

Пример 04.001.01-2011

• Интерфейсы выделены в отдельную фабрику

• Главное приложение явно зависит только от интерфейсов

• Выбор семейства классов можно настраивать из файла конфигурации.

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

Page 14: ук 03.003.01 2011

Известные применения

• System.DataCommon.DbProviderFactory (ADO .Net) static DbConnection CreateDbConnection( string providerName, string connectionString)

{

DbConnection connection = null;

if (connectionString != null)

{

try

{

DbProviderFactory factory = DbProviderFactories.GetFactory(providerName);

connection = factory.CreateConnection();

connection.ConnectionString = connectionString;

}

catch (Exception ex)

{

if (connection != null)

{

connection = null;

}

Console.WriteLine(ex.Message);

}

}

return connection;

}

Page 15: ук 03.003.01 2011

Методы DbProviderFactory

• CreateCommand Возвращает новый экземпляра класса поставщика, реализующий класс DbCommand.

• CreateCommandBuilder Возвращает новый экземпляра класса поставщика, реализующий класс DbCommandBuilder.

• CreateConnection Возвращает новый экземпляра класса поставщика, реализующий класс DbConnection.

• CreateConnectionStringBuilder Возвращает новый экземпляра класса поставщика, реализующий класс DbConnectionStringBuilder.

• CreateDataAdapter Возвращает новый экземпляра класса поставщика, реализующий класс DbDataAdapter.

• CreateDataSourceEnumerator Возвращает новый экземпляра класса поставщика, реализующий класс DbDataSourceEnumerator.

• CreateParameter Возвращает новый экземпляра класса поставщика, реализующий класс DbParameter.

• CreatePermission Возвращает новый экземпляра класса поставщика, реализующий версию поставщика класса CodeAccessPermission.

Page 16: ук 03.003.01 2011

Родственные паттерны

• Фабричный метод

• Прототип

• Одиночка

Page 17: ук 03.003.01 2011

Строитель

Категория: паттерн, порождающий объекты

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

Page 18: ук 03.003.01 2011

Мотивация

• Предположим, что процесс инициализации объекта происходит не в одно действие

• Часто это является причиной для использования конструктора с пустым набором параметров и инициализации объекта через набор полей

Например, HTTP/FTP запрос или ответ

1. Указать заголовки

2. Указать URL запроса

3. Задать тело запроса (если есть).

Page 19: ук 03.003.01 2011

private void RegisterFile(Guid guid, String fileExt)

{

using (SqlConnection connection = new SqlConnection(connectionString))

{

SqlCommand dbCommand = new SqlCommand("mm_File_Register", connection);

dbCommand.CommandType = CommandType.StoredProcedure;

dbCommand.Parameters.Add(new SqlParameter("guid", SqlDbType.UniqueIdentifier));

dbCommand.Parameters.Add(new SqlParameter("storage_path", SqlDbType.VarChar, 50));

dbCommand.Parameters.Add(new SqlParameter("profile_name", SqlDbType.VarChar, 256));

dbCommand.Parameters.Add(new SqlParameter("file_ext", SqlDbType.VarChar, 256));

dbCommand.Parameters["guid"].Value = guid;

dbCommand.Parameters["storage_path"].Value = FileStorage.BasePath;

dbCommand.Parameters["profile_name"].Value = profile;

dbCommand.Parameters["file_ext"].Value = fileExt; // Image

dbCommand.Connection.Open();

dbCommand.ExecuteNonQuery();

dbCommand.Connection.Close();

}

}

private bool ConvertOriginal(Stream original, out byte[] bytes)

{

Image image;

var origBytes = ReadAllBytes(original);

using (var origStream = new MemoryStream(origBytes))

{

try { image = Image.FromStream(origStream); }

catch (ArgumentException ex) { throw new BadImageException(ex); }

var format = ImageFormat.OriginalImageFormat(image);

if (format == null)

{

bytes = origBytes;

return false;

}

else

{

var convBytes = ImageConverter.Convert(origStream, format);

if (convBytes.Length < origBytes.Length) { bytes = convBytes; return true; }

else { bytes = origBytes; return false; }

}

}

}

Page 20: ук 03.003.01 2011

Замечания к примеру

• Нарушение принципа единственной ответственности – Создаем хранилище

– Преобразование графических данных к указанному формату

– Файл с неграфическими данными сохраняется в хранилище под именем “f” c текущим расширением, возможно, здесь добавлено поведение, что может быть только один файл для каждого расширения, а может быть имя файла не так важно, а важен guid, под котором файл зарегистрирован в базе данных

• Преобразование графического изображения идет после сохранения в хранилище первого варианта, значит два раза пишем на ftp сервер

• Получение расширения по имени файла

• Отсутствие транзакционности (можно зарегистрировать файл, но при этом не записать его в хранилище)

Page 21: ук 03.003.01 2011

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

• Если структура объекта сложная, то она либо будет меняться, а значит и сам алгоритм инициализации, либо будет необходимо иметь несколько различных реализаций (надо избежать copy-paste алгоритма инициализации)

• Если данные нельзя получить одномоментно, то их необходимо где-то накапливать, чтобы потом создать полностью проинициализированный объект (контрактная модель).

• Надо отделить вызов конструктора и передачи в него параметров от алгоритма инициализации.

Page 22: ук 03.003.01 2011

• Весь алгоритм инициализации разбивается на несколько шагов.

• Результат каждого шага – изолированная порция информации, необходимая для корректной инициализации конечного объекта

• Для примера 2: – Подготовка данных к сохранению,

– Создать пустой файл

– Сохранить данные в файл

– Регистрация файла в базе.

Page 23: ук 03.003.01 2011

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

• Алгоритм создания сложного объекта не должен зависеть от того, из каких частей состоит объект и как они стыкуются между собой;

• Процесс конструирования должен обеспечивать различные представления конструируемого объекта

Page 24: ук 03.003.01 2011

Структура

Page 25: ук 03.003.01 2011

Результаты

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

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

• Управление процессом конструирования.

• Побочные эффекты: – Результатом конструирования могут быть совершенно разные объекты, не имеющих между

собой ничего общего. Например, 1. матрица – либо сама матрица, либо признак – является она диагональной или нет. 2. Алгоритм конвертера – либо обработанные объявления в базе, либо отчет об ошибках в файл.

– Иногда Builder используется для оптимизации производительности (StringBuilder из .Net) – Упрощает применение Mock объектов при организации модульного тестирования

Page 26: ук 03.003.01 2011

Вопросы реализации

• Интерфейс сборки и конструирования – Чаще всего Director не требуется доступ к частям конструируемого

объекта, поэтому интерфейс Builder ориентирован только на передачу параметров в одну сторону от Builder к Director

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

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

• Жирные интерфейсы в билдере нежелательны, но допустимы, поскольку набор методов обусловлен алгоритмом инициализации, а не конечным представлением результата иниуциализации.

Page 27: ук 03.003.01 2011

Пример 04.002.01-2011

Page 28: ук 03.003.01 2011

Известные применения

• System.Data.Common.DBConnectionStringBuilder

• System.Text.StringBuilder

Page 29: ук 03.003.01 2011

Родственные паттерны

• Абстрактная фабрика

• Компоновщик (как правило строитель используется для конструирования составных объектов)

Page 30: ук 03.003.01 2011

Прототип

• Категория: паттерн, порождающий объекты

• Назначение: Задает виды создаваемых объектов с помощью экземпляра-прототипа и создает новые объекты путем копирования этого прототипа

Page 31: ук 03.003.01 2011

Мотивация

• Объявление

Цель: заявить о чем-либо, чтобы получить желаемую реакцию аудитории

• Форма сообщения – Зависит от способа доставки сообщения

– Зависит от желания заявителя (например, кредитный калькулятор)

• Способ доставки сообщения до потребителя

• Проспект – каналы доставки сообщений до целевой аудитории

Page 32: ук 03.003.01 2011

• Рано или поздно функционал стабилизируется (содержание) • Начинает меняться форма Дифференцируйся или умирай! (Джек Траут) MS Office, MS Windows Дизайн Город55 • Внутренняя структура усложняется, часто нет никаких разумных

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

проинициализированными объектами Например, объявление – структуру полей можно взять из конвертора

Page 33: ук 03.003.01 2011

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

• Инстанцируемые классы определяются во время выполнения

• Для того, чтобы избежать построения иерархий классов или фабрик, параллельных иерархии классов продуктов

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

Page 34: ук 03.003.01 2011

Структура

Page 35: ук 03.003.01 2011

Результаты

• Те же, что у абстрактной фабрики и строителя

• Добавление и удаление продуктов во время выполнения

• Спецификация новых объектов путем изменения значений

Вместо нескольких классов, создается несколько объектов одного класса, отличающихся своим состоянием

Например, объявление

• Спецификация объектов путем изменения структуры

Например, рубрика параметризуется экземпляром объявления, которое можно подавать в данную рубрику

• Уменьшение числа подклассов

• Динамическое конфигурирование приложения прототипами

Page 36: ук 03.003.01 2011

Вопросы реализации

• Использование диспетчера прототипов

(ассоциативный массив, хранящий каждый прототип по ключу)

• Реализация операции Clone – Поверхностное и глубокое копирование

– IСloneable

• Инициализация клонов

Page 37: ук 03.003.01 2011

Известные применения

• ArrayList

• Метод MemberwiseClone класса object

Page 38: ук 03.003.01 2011

Родственные паттерны

• Расширяемая абстрактная фабрика может строиться на основе прототипов

• Часто применяется там же, где компоновщик и декоратор.

Page 39: ук 03.003.01 2011

Фабричный метод

• Категория: паттерн, порождающий объекты

• Назначение: Определяет интерфейс для создания объекта, но оставляет подклассам решение какой класс инстанцировать.

• Синоним: Виртуальный конструктор

Page 40: ук 03.003.01 2011

Мотивация

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

Page 41: ук 03.003.01 2011

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

• Классу заранее неизвестно, объекты каких классов ему нужно создавать

• Класс спроектирован так, что чтобы объекты, которые он создает, специфицировались подклассами

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

(например, для определения стратегий)

Page 42: ук 03.003.01 2011

Структура

Page 43: ук 03.003.01 2011

Результаты

• Предоставляет классам операции-зацепки (hooks)

• Соединяет параллельные иерархии

Page 44: ук 03.003.01 2011

Реализация

• Две основных реализации – Creator – абстрактный класс

– Creator – конкретный класс

• Параметризованные фабричные методы

• Generic типы, чтобы не порождать подклассы class Creator<T>

{

T Create()

{

return new T();

}

}

• Extenders .Net можно использовать в качестве фабричных методов

• Соглашение об именах

Page 45: ук 03.003.01 2011

Известные применения

• DBConnection

protected abstract DbCommand CreateDBCommand()

• XMLSerialzier.CreateReader

protected virtual XmlSerializationReader CreateReader()

Page 46: ук 03.003.01 2011

Родственные паттерны

• Абстрактная фабрика часто реализуется с помощью фабричных методов

• Фабричные методы часто применяются внутри шаблонных методов, например, для создания стратегий

Page 47: ук 03.003.01 2011

Синглетон

• Категория: паттерн, порождающий объекты

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

Page 48: ук 03.003.01 2011

Мотивация

• Для некоторых классов, важно, чтобы существовал ровно один экземпляр, например, расширяемая фабрика

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

• Класс сам должен контролировать количество экземпляров, которое можно создать.

• Контроль возможно осуществлять только из методов.

Page 49: ук 03.003.01 2011

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

• Должен быть ровно один экземпляр некоторого класса, легко доступный всем клиентам;

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

Page 50: ук 03.003.01 2011

Структура

Page 51: ук 03.003.01 2011

Результаты

• Контролируемый доступ к единственному экземпляру

• Уменьшение числа имен

• Допускает уточнение операций и представления

• Допускает переменное число экземпляров

• Большая гибкость, чем у операций класса.

Паттерн MonoState. Все поля и методы сделать статическими, чтобы гарантировать, что есть ровно один экземпляр. Но тогда нельзя использовать наследование.

Page 52: ук 03.003.01 2011

Реализация

• Гарантирование одного экземпляра class Singleton

{

public static Singleton Instance()

{

get

{

return instance;

}

}

private Singleton()

{

}

private static Singleton()

{

instance = new Singleton();

}

private static Singleton instance;

}

Page 53: ук 03.003.01 2011

• Порождение подклассов class Singleton

{ public static void Register(string name, Type type) ,…-

public static Singleton Instance

{

get

{

if(!instance)

{

instance = CreateInstanceByType(Lookup(Detect()));

}

return instance;

}

}

private static Type Lookup(name) ,…-

private static string Detect() ,…- //Определяет имя класса Singleton, которым должна быть сконфигурирована система

private static Singleton instance;

}

Page 54: ук 03.003.01 2011

• Уничтожение синглетонов – утечка ресурсов

– Висячая ссылка

Пример: Порядок уничтожения нескольких синглетонов

Display, Keyboard, Log

Варианты решения: феникс, синглетон с заданной продолжительностью жизни

Page 55: ук 03.003.01 2011

• Феникс interface ISingleton

{

void DoSometing();

}

class Singleton: ISingleton

{

public static ISingleton Instance

{

get

{

if(!instance)

{

instance = new Singleton();

}

return new SingletonPhenix();

}

}

}

class SingletonPhenix: ISingleton

{

public virtual DoSomething()

{

Singleton.Instance.DoSomething();

}

internal SingletonPhenix();

}

• Не хранить ссылки на синглетон, везде использовать вызов свойства Instance

• Состояние разрушенного объекта теряется

Page 56: ук 03.003.01 2011

• Синглетон с заданной продолжительностью жизни – Каждому синглетону ставится в соответствие целое число –

“продолжительность жизни”.

– Список всех синглетонов упорядочивается по продолжительности жизни.

– Синглетоны уничтожаются в порядке увеличения продолжительности жизни.

– Сам список – это тоже синглетон с наибольшей продолжительностью жизни.

– Необходим интерфейс по регистрации синглетонов в общем списке.

Page 57: ук 03.003.01 2011

• Многопоточная среда private static object locker;

public static Singleton Instance

{

lock(locker)

{

if(!instance)

{

instance = new Singleton();

}

return instance; }

}

– Неприемлемо из-за больших накладных расходов на блокировку

Page 58: ук 03.003.01 2011

Пример 04.006.01-2011

Page 59: ук 03.003.01 2011

Известные применения

• AppDomain

public static AppDomain CurrentDomain { get; }

• Application

public static Application Current { get; }

Page 60: ук 03.003.01 2011

Родственные паттерны

• Абстрактная фабрика часто реализуется в виде Синглетона

Page 61: ук 03.003.01 2011

Адаптер

• Категория: структурный паттерн

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

• Синоним: Wrapper(Обертка)

Page 62: ук 03.003.01 2011

Мотивация

• Есть готовый класс, который предоставляет нужную функциональность.

• Но интерфейс класса не позволяет использовать его непосредственно без изменения.

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

• Согласно открыто-замкнутому принципу, существующий класс модифицировать нельзя.

• Выход: создать класс с нужным интерфейсом, но который реализует его через вызов методов существующего класса.

Аналог адаптеров в жизни: адаптеры(переходники) для розеток.

Page 63: ук 03.003.01 2011

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

• Надо использовать существующий класс, но его интерфейс не соответствует текущим потребностям

• Надо создать повторно используемый класс, который должен взаимодействовать с заранее неизвестными и не связанными с ним классами, имеющими несовместимый между собой интерфейс

(Программа Copy, УК 01.001)

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

Page 64: ук 03.003.01 2011

Структура (адаптер классов)

Page 65: ук 03.003.01 2011

Структура (адаптер объектов)

Page 66: ук 03.003.01 2011

Результаты (адаптер объектов)

• (+) Один адаптер может применяться ко многим классам (базовый класс и его подклассы). Адаптер добавляет новую функциональность сразу всем адаптируемым классам.

• (-) Для замещения операций класса Adaptee надо создать класс производный от Adaptee и сделать так, чтобы адаптер ссылался на этот новый класс

Page 67: ук 03.003.01 2011

Реализация

• Объем работы по адаптации • Сменные адаптеры Применяется для уменьшения количества предположений о классах, с

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

Пример: Универсальная форма по вводу объявлений – Абстрактные операции (лучше не использовать так, как противоречит принципу

обращения зависимостей) Пример: специализация формы для каждого вида объявлений

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

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

interface IAd { void Add(Field field); }

– Параметризованные адаптеры Пример: биндинг данных на форму, шаблон объявления

• Двусторонние адаптеры

Page 68: ук 03.003.01 2011

Пример 04.007.01-2011

Page 69: ук 03.003.01 2011

Известные применения

• Adapter Represents a base class for the adapter developed using the WCF LOB Adapter SDK.

Namespace: Microsoft.ServiceModel.Channels.Common

Assembly: microsoft.servicemodel.channels.dll

• Adapter Используется для адаптации логики отдельных элементов.

Namespace: Microsoft.Windows.Design.Interaction

Assembly: Microsoft.Windows.Design.Extensibility.dll

• cHTML Adapter Set The cHTML adapter set renders ASP.NET mobile Web pages on clients that are capable of rendering HTML 3.2 but do not support client scripting. This adapter set includes special support for cHTML, the markup language used on i-mode phones.

Page 70: ук 03.003.01 2011

Родственные паттерны

• Мост реализуется аналогично адаптеру, но у моста другое назначение.

• Декоратор очень похож на адаптер, но используется по-другому.

Page 71: ук 03.003.01 2011

Компоновщик

• Категория: паттерн, структурирующий объекты

• Назначение: Компонует объекты в древовидные структуры для представления иерархий “part of”. Позволяет клиентам единообразно трактовать индивидуальные и составные объекты.

Page 72: ук 03.003.01 2011

Мотивация

• Объекты в программе образуют иерархии “part of”.

Например, объявление и поле объявления; поле, в свою очередь может быть составным, например, площадь жилой недвижимости.

• Какие иерархии являются “правильными” с точки зрения ООП?

• По аналогии с принципом подстановки Лисков: надо единообразно трактовать атомарные и составные объекты.

• Значит атомарные и составные объекты должны иметь общий интерфейс

Page 73: ук 03.003.01 2011

Структура

Page 74: ук 03.003.01 2011

Структура типового составного объекта

Page 75: ук 03.003.01 2011

Результаты

• Определяет иерархии классов, состоящие из примитивных и составных объектов.

• Упрощает архитектуру клиента.

• Облегчает добавление новых видов компонентов.

Изменять клиента при добавлении новых компонентов не нужно.

• Способствует созданию общего дизайна.

Трудно ограничить, чтобы составной компонент включал только определенные виды компонентов.

Page 76: ук 03.003.01 2011

Реализация

• Явные ссылки на родителей

• Разделение компонентов (паттерн Приспособленец)

• Максимизация интерфейса класса Component

• Объявление операций для управления потомками (исключение из принципа соответствия интерфейсов, УК 03.001)

• Должен ли Component реализовывать список компонентов

• Упорядочивание потомков (паттерн Итератор)

• Кэширование для повышения производительности

• Кто должен удалять компоненты

• Какая структура данных лучше всего подходит для хранения компонентов (паттерн Интерпретатор)

Page 77: ук 03.003.01 2011

Пример кода (ПР 04.008.01-2011)

Page 78: ук 03.003.01 2011

Известные прменения

• Control - класс (System.Windows.Controls, System.Web.UI, System.Windows.Forms)

• XMLNode (System.XML)

Page 79: ук 03.003.01 2011

Родственные паттерны

• Цепочка обязанностей использует паттерн Компоновщик

• Декоратор часто совместно используется с компоновщиком

• Паттерн приспособленец позволяет разделять компоненты

• Итератор может использоваться для обхода составных объектов

• Посетитель локализует операции и поведение, которое пришлось бы распределять между классами Composite и Leaf.

Page 80: ук 03.003.01 2011

Фасад

• Категория: паттерн, структурирующий объекты

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

Page 81: ук 03.003.01 2011

Мотивация

• Есть сторонний компонент, который хотелось бы использовать в приложении

• Приложение не должно зависеть от используемого компонента

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

• Полученный набор классов и будет фасадом.

Page 82: ук 03.003.01 2011

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

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

• Между клиентами и классами реализации существует много зависимостей. Фасад позволяет отделить подсистему как от клиентов, так и от других подсистем.

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

Page 83: ук 03.003.01 2011

Структура

Page 84: ук 03.003.01 2011

Результаты

• Изолирует клиентов от компонентов под системы

• Позволяет ослабить связность между под системой и ее клиентами.

• Фасад не препятствует приложениям обращаться напрямую к классам подсистемы, если это необходимо.

Page 85: ук 03.003.01 2011

Реализация

• Уменьшение степени связности.

• Закрытые и открытые классы подсистем.

Page 86: ук 03.003.01 2011

Пример кода (ПР 04.009.01-2011)

Page 87: ук 03.003.01 2011

Известные применения

• Платформа .Net – WinForms, WPF

– ADO .Net

– WCF, Remoting

Page 88: ук 03.003.01 2011

Родственные паттерны

• Абстрактная фабрика (для создания фасада, как альтернатива)

• Посредник

• Адаптер

• Декоратор

• Синглетон

• Мост

• Итератор

Page 89: ук 03.003.01 2011

Наблюдатель

• Категория: паттерн поведения объектов

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

• Синоним: Dependends (Подчиненные), Publish-Subscribe (издатель-подписчик).

Page 90: ук 03.003.01 2011

Мотивация

• Объект класса Subject меняет свое состояние с течением времени

• Есть несколько других объектов разных классов, которым необходимо знать об этих изменениях.

• Зашивать в код Subject информирование этих объектов об изменении состояния противоречит открыто-замкнутому принципу – могут появиться новые.

• Описываем поведение, которое отвечает за информирование объектов в отдельный интерфейс IObserver.

• Вызываем методы IObserver из класса Subject.

Page 91: ук 03.003.01 2011

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

• У абстракции есть два аспекта, из которых один зависит от другого. Наблюдатель позволяет инкапсулировать эти аспекты в разные объекты и изменять и повторно использовать независимо друг от друга.

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

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

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

Page 92: ук 03.003.01 2011

Структура

Page 93: ук 03.003.01 2011

Результаты

• Абстрактная связность наблюдаемого объекта и наблюдателя

Побочные эффекты

• Поддержка широковещательных коммуникаций

• Неожиданные обновления

Page 94: ук 03.003.01 2011

Реализация

• Отображение субъектов на наблюдателей

Пример: event предоставляет возможность переопределять механизм подписки с помощью методов Add и Remove

Пример: Ex 04.011.01-2011

• Наблюдение более чем за одним объектом

Пример: Обработчики событий содержат объект-источник события

• Кто инициирует обновление

Push и pull-модели получения информации

• Как избежать зависимости протокола обновления от наблюдателя:

Push и pull-модели получения информации

Page 95: ук 03.003.01 2011

• Висячие ссылки на удаленные наблюдаемые объекты

• Гарантия непротиворечивости состояния перед отправкой уведомления

Легко нарушить, если вызывать унаследованные методы базового класса из переопределенных методов наследника.

class Ad

{

public virtual void Load()

{

Notify();

}

}

class AutoAd: Ad

{

public override void Load()

{

base.Load();

this.model = storage*“model”+;

this.marka = storage*“marka”+;

}

}

Page 96: ук 03.003.01 2011

• Подписка только на интересующие модификации

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

• Комбинирование классов Subject и Observer

• Инкапсуляция сложной семантики обновления

Нужно: – отношения зависимости между объектами становятся сложными,

– Необходимо выполнить серию однотипных обновлений, выполнение обновления выполняется достаточно долго

Примеры:

1. Ведение логов.

2. Расчет квот.

Page 97: ук 03.003.01 2011
Page 98: ук 03.003.01 2011

• Синхронная и асинхронная обработка обновлений

GUI обрабатывается в одном потоке

• Интеграция приложений

Page 99: ук 03.003.01 2011

Пример кода

• Ex 04.010.01-2011 (рекомендации Microsoft по использованию событий)

• Ex 04.011.01-2011 (отображение субъекта на наблюдатели)

Page 100: ук 03.003.01 2011

Идеи по проектам

• Медленно работает конвертор – Делать проверки для группы объявлений

• Фотопроцессор – Сообщение с заданием на конвертацию

Page 101: ук 03.003.01 2011

Известные применения

• Обработка событий в любом GUI

• Механизм подписки через events и delegates платформы .Net

• WPF

• Паттерны интеграции корпоративных приложений

Page 102: ук 03.003.01 2011

Родственные паттерны

• Команда: обработчики событий

• Цепочка ответственности: маршрутизация событий

• Посредник: сложные случаи обновления данных

Page 103: ук 03.003.01 2011

Команда

• Категория: паттерн поведения объектов

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

• Синоним: Action, Transaction.

Page 104: ук 03.003.01 2011

Мотивация

• Есть класс, который знает когда нужно выполнить действие, но не знает какое, и есть класс, который знает какое действие выполнить, но не знает, когда

Например, текстовое поле

• Выделяем интерфейс Command, который описывает поведение Выполнить действие

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

Page 105: ук 03.003.01 2011

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

• Необходимо параметризовать объекты выполняемым действием – альтернатива функциям обратного вызова

Пример: – Алгоритм быстрой сортировки

– Обработчик событий формы

• Определять, ставить запросы в очередь, выполнять в разное время (даже в другом адресном пространстве)

• Поддерживать отмену операций

• Поддерживать протоколирование изменений

• Структурировать систему на основе высокоуровневых операций, построенных из примитивных.

Page 106: ук 03.003.01 2011

Структура

Page 107: ук 03.003.01 2011

Результаты

• Разрыв связи между объектом, вызывающим операцию и объектом, знающим, как эту операцию выполнить

• Команда – полноценный объект, которым можно манипулировать и расширять

Побочные эффекты

• Из простых команд можно собирать составные

• Добавлять новые команды легко

Page 108: ук 03.003.01 2011

Реализация

• Степень смышлености команды

Две крайности: – Вызов операций получателя

– Самостоятельное выполнение всех операций

• Поддержка повтора и отмены операций

Дополнительный метод Unexecute Выполняет действие обратное к действию Execute

Например: символа ‘a’ в 5 строке 3 символ – удалить 3 символ в пятой строке

Page 109: ук 03.003.01 2011

• Макрокоманды

Для реализации применяется паттерн компоновщик

Вопросы реализации: – Видит ли следующая команда измененные значения out

параметров

– Если команды возвращают значение, то что будет возвращать макрокоманда

– Если одна из команд генерирует исключение, то продолжать выполнение остальных и, если нет, то следует ли выполнять откат уже выполненных команд?

• Накопление ошибок в процессе отмены

Сохранять немного больше информации, чем это необходимо для выполнения операции

Page 110: ук 03.003.01 2011

Пример кода

Ex 04.012.01-2011

Page 111: ук 03.003.01 2011

Известные применения

• delegate

• Action<T>

Page 112: ук 03.003.01 2011

Родственные паттерны

• Компоновщик для создания макрокоманд

• Хранитель для запоминания информации необходимой для отмены команды

• Прототип, если необходимо копировать команду, например, для сохранения в истории

• Команда используется совместно с наблюдателем для того, чтобы снизить зависимость наблюдаемого объекта от деталей наблюдателя

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

Page 113: ук 03.003.01 2011

Приспособленец

• Категория: структурный паттерн

• Назначение: Оптимизация использования ресурсов в случае множества мелких объектов

Page 114: ук 03.003.01 2011

Мотивация

• Слишком большие расходы на хранение объектов

Часто является причиной отказа от ООП

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

• Сущности чем-то отличаются между собой

• Различие в сущностях выражается в разных значениях данных

• Надо придумать способ вычисления данной информации по набору данных, меньшему по объему, чем прямое хранение данных

Page 115: ук 03.003.01 2011

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

• большое число объектов, из-за этого накладные расходы на хранение высоки

• Большую часть состояния объекта можно вынести вовне

• Многие группы объектов можно заменить небольшим количеством разделяемых объектов

• Приложение не зависит от идентичности объекта

Примеры:

Автоматы, схемы электрической цепи (любые диаграммы), векторная графика, текстовый редактор

Page 116: ук 03.003.01 2011

Структура

Page 117: ук 03.003.01 2011

Результаты

• Уменьшение объема памяти

Побочные эффекты

• Сокращение числа экземпляров

• Вычисление, а не хранение внешнего состояния

Page 118: ук 03.003.01 2011

Реализация

• Управление разделяемыми объектами

• Вынесение внешнего состояния

Page 119: ук 03.003.01 2011
Page 120: ук 03.003.01 2011

Пример кода

Ex 04.013.01-2011

Page 121: ук 03.003.01 2011

Известные применения

?

Page 122: ук 03.003.01 2011

Родственные паттерны

• Компоновщик. Ациклический направленный граф с разделяемыми листовыми вершинами.

• Состояние и стратегия часто реализуются через Приспособленца

• Хранитель для сохранения внешнего состояния Приспособленца

Page 123: ук 03.003.01 2011

Хранитель

• Категория: паттерн поведения объектов

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

• Синоним: Token.

Page 124: ук 03.003.01 2011

Мотивация

• Есть объект Хозяин, состояние которого надо хранить дольше, чем время жизни процесса, его создавшего

• При сохранении состояния объекта необходимо иметь доступ ко внутренним данным

• Предоставление доступа ко внутренним данным ведет к нарушению инкапсуляции

• Выход: создать класс Хранитель, который будет частью реализации объекта Хозяина и который будет заключать в себе внутренне состояние Хозяина.

• Чтобы не было нарушения инкапсуляции класс Хранитель должен предоставлять два интерфейса – “открытый” для хранилища, куда будет записываться состояние объекта и “расширенный” – доступный только для Хозяина.

Page 125: ук 03.003.01 2011

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

• Необходимо сохранить мгновенный снимок объекта или его части, чтобы потом можно было восстановить в нем объект

• Прямой доступ к этому состоянию нарушает инкапсуляцию и раскрывает детали реализации

Page 126: ук 03.003.01 2011

Структура

Page 127: ук 03.003.01 2011

Результаты

• Сохранение границ инкапсуляции

• Упрощение структуры хозяина

• Значительные издержки при использовании хранителей

• Скрытая плата за содержание хранителя

Побочные эффекты

• Определение “узкого” и “широкого” интерфейсов

Page 128: ук 03.003.01 2011

Пример кода

Ex 04.014.01-2011

Page 129: ук 03.003.01 2011

Известные применения

• ORM

• ?

Page 130: ук 03.003.01 2011

Родственные паттерны

• Команда: Хранитель используется для хранения внутреннего состояния команд

• Итератор: С помощью итератора осуществляется перебор хранителей в Хранилище

• Приспособленец использует Хранителя для манипуляции состояния, выносимого за пределы приспособленца

Page 131: ук 03.003.01 2011

Шаблонный метод

• Категория: паттерн поведения объектов

• Назначение: Определяет основу алгоритма и позволяет подклассам переопределять некоторые шаги алгоритма, не изменяя его структуру в целом.

Page 132: ук 03.003.01 2011

Мотивация

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

• Выделяем набор блоков, в каждой из функций.

• Каждый из этих блоков оборачиваем вызовом операции.

• Полученные операции образуют набор примитивных операций и функций-зацепок.

• Преобразованный метод реализует паттерн Шаблонный метод.

Page 133: ук 03.003.01 2011

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

• Повторно использовать неизменные части алгоритма, позволяя подклассам переопределять реализацию изменяющегося поведения

• Для управления расширениями подклассов. Точки расширения – функции-зацепки.

Page 134: ук 03.003.01 2011

Результаты

• Шаблонные методы приводят к инвертированной структуре кода (принцип обращения зависимостей)

• Шаблонные методы вызывают операции следующих видов: – Конкретные операции (из ConcreteClass, либо из клиента)

– Конкретные операции из AbstractClass

– Примитивные операции

– Фабричные методы

– Операции-зацепки (операции, имеющие реализацию по умолчанию, которые могут быть переопределены в подклассах)

Page 135: ук 03.003.01 2011

Структура

Page 136: ук 03.003.01 2011

Реализация

• Контроль доступа (видимость, абстрактные операции)

• Сокращение числа примитивных операций

• Соглашение об именах Например, имена замещаемых операций начинаются с префикса Do

Page 137: ук 03.003.01 2011

Пример кода

• Ex 04.015.01-2011

Page 138: ук 03.003.01 2011

Известные применения

• XpathNavigator (System.XML.XPath) – NameTable – Clone – NodeType – LocalName – Name – NamespaceURI – Prefix – BaseURI – IsEmptyElement – MoveToFirstAttribute – MoveToNextAttribute – MoveToFirstNamespace – MoveToNextNamespace – MoveToNext – MoveToPrevious – MoveToFirstChild – MoveToParent – MoveTo – MoveToId – IsSamePosition – Value

– AppendChild – CreateAttribute – CreateAttributes – CreateNavigator

Page 139: ук 03.003.01 2011

Родственные паттерны

• Фабричные методы часто вызываются в шаблонах

• Стратегии применяются для делегирования модификации алгоритма в целом

Page 140: ук 03.003.01 2011

Стратегия

• Категория: паттерн поведения объектов

• Назначение: Определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми.

• Синоним: Policy (Политика).

Page 141: ук 03.003.01 2011

Мотивация

• Есть несколько операторов switch или цепочек if-else-if

• Такие конструкции противоречат Открыто-замкнутому принципу, так как делают программу нерасширяемой

• Заменим каждый switch или цепочку if-else-if на полиморфную операцию

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

• Перенесем все выделенные операции в один интерфейс.

• Те реализации функций, которые должны использоваться совместно реализуем в одном классе-наследнике от выделенного интерфейса.

Page 142: ук 03.003.01 2011

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

• Имеется много родственных классов, отличающихся только поведением

• Необходимо иметь несколько вариантов алгоритма

• В алгоритме содержатся данные, о которых клиент не должен знать

• В классе определено много поведений, которые представлены разветвленными условными операторами

Page 143: ук 03.003.01 2011

Структура

Page 144: ук 03.003.01 2011

Результаты

• Семейства родственных алгоритмов

• Альтернатива порождению подклассов

• С помощью стратегий можно избавиться от условных операторов

• Выбор реализации

Побочные эффекты

• Клиенты должны знать о различных стратегиях

• Увеличение числа объектов

• Обмен информацией между стратегией и контекстом

Page 145: ук 03.003.01 2011

Реализация

• Обмен данными между стратегией и контекстом

• Стратегии как параметры generic-типов

Page 146: ук 03.003.01 2011

Пример кода

• Ex 04.016.01-2011

• Ex 04.017.01-2011

Page 147: ук 03.003.01 2011

Известные применения

• XMLSerializationReader, XMLSerializationWriter

• IComparable

• IDisposable

• IConvertible

Page 148: ук 03.003.01 2011

Родственные паттерны

• Объекты-стратегии удобно реализовывать в виде приспособленцев

• Стратегии используются для параметризации шаблонного метода

Page 149: ук 03.003.01 2011

Посредник

• Категория: паттерн поведения объектов

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

• Синоним: Controller (Контроллер).

Page 150: ук 03.003.01 2011

Мотивация

• В системе много классов, которые сильно связаны между собой (каждый с каждым).

• Получаем нарушение открыто-замкнутого принципа.

• Идея: прием как в случае отношения “многие-ко-многим” – создать объект, с которым будут взаимодействовать все остальные.

• Тогда все остальные объекты можно использовать повторно.

Page 151: ук 03.003.01 2011

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

• Имеются объекты, связи между которыми сложны и нечетко определены, взаимозависимости трудны для понимания.

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

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

Page 152: ук 03.003.01 2011

Структура

Page 153: ук 03.003.01 2011

Результаты

• Устраняет связность между коллегами

• Упрощает протоколы взаимодействия объектов

• Абстрагирует способ кооперирования объектов

Побочный эффект

• Централизует управление

• Снижает число порождаемых подклассов

Page 154: ук 03.003.01 2011

Пример кода

• Ex 04.018.01-2011

Page 155: ук 03.003.01 2011

Известные применения

• MVC (ASP .Net MVC Framework, BL)

• Форма приложения часто является посредником для своих дочерних элементов

Page 156: ук 03.003.01 2011

Родственные паттерны

• Фасад часто реализуется как совокупность посредников.

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

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

Page 157: ук 03.003.01 2011

Декоратор

• Категория: паттерн структурирующий объекты

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

• Синоним: Wrapper (Обертка).

Page 158: ук 03.003.01 2011

Мотивация

• Есть иерархия классов, ко всем объектам которой необходимо добавить дополнительное поведение на время выполнения одной операции.

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

• Значит надо создать новый класс. • Чтобы не нарушить принцип подстановки Лисков, надо чтобы новый класс

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

что и базовый класс иерархии. • Чтобы не дублировать поведение существующих классов, новый должен

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

• Это возможно, если новый класс будет хранить ссылку на декорируемый объект и делегировать ему выполнение всех операций.

Page 159: ук 03.003.01 2011

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

• Динамическое, прозрачное для клиентов добавление обязанностей

• Реализация обязанностей, которая может быть снята с клиента.

• Замена расширения с помощью подклассов.

Page 160: ук 03.003.01 2011

Структура

Page 161: ук 03.003.01 2011

Результаты

• Большая гибкость, чем у статического наследования.

• Уменьшает количество перегружаемых функций на верхних уровнях иерархии классов.

Побочные эффекты:

• Декоратор и его компонент не идентичны.

• Множество мелких объектов.

Page 162: ук 03.003.01 2011

Реализация

• Соответствие интерфейсов

• Отсутствие абстрактного класса декоратор

• Облегченные классы Component

• Изменение внешнего поведения, а не реализации

Page 163: ук 03.003.01 2011

Пример кода

Page 164: ук 03.003.01 2011

Известные применения

• System.Reflection.TypeDelegator

protected Type typeImpl

• ReadOnly коллекции

public static IList ArrayList.ReadOnly( IList list );

• Исправление ошибки в библиотеке работы с MySQL на Qt3

Page 165: ук 03.003.01 2011

Родственные паттерны

• Адаптер vs. Декоратор

• Декоратор можно реализовывать как – Singleton

– Flyweight

Page 166: ук 03.003.01 2011

Итератор

• Категория: паттерн поведения объектов

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

• Синоним: Cursor.

Page 167: ук 03.003.01 2011

Мотивация

• Есть алгоритм, который перебирает элементы некоторого составного объекта

• Способ перебора элементов – это деталь реализации составного объекта

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

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

• Выделенный интерфейс и будет иетратором.

Page 168: ук 03.003.01 2011

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

• Доступ к содержимому составных объектов, не раскрывая деталей реализации.

• Несколько активных обходов одного составного объекта

• Единообразный интерфейс обхода для разных составных объектов.

Page 169: ук 03.003.01 2011

Структура

Page 170: ук 03.003.01 2011

Результаты

• Различные виды обходов составного объекта

• Упрощение интерфейса составного объекта

• Несколько активных обходов одного и того же составного объекта

Побочный эффект

• Изменение в структуре составного объекта может повлиять на активные обходы

Page 171: ук 03.003.01 2011

Реализация

• С++ и Java-стиль итераторов – С++-стиль

ContainerType C; // Любой стандартный тип контейнера, например std::list<sometype> //for (ContainerType::iterator it = C.begin(),end = C.end(); it != end; ++it) //(если вам нужно изменять элементы) for (ContainerType::const_iterator it = C.begin(),end = C.end(); it != end; ++it) { std::cout << *it << std::endl; }

ContainerType<ItemType> C; // Любой стандартный тип контейнера элементов ItemType

void ProcessItem( const ItemType& I ) // Функция, обрабатывающая каждый элемент коллекции { std::cout << I << std::endl;

}

std::for_each( C.begin(), C.end(), ProcessItem ); // Цикл просмотра

Page 172: ук 03.003.01 2011

– Java-стиль

// 'явная' версия

IEnumerator<MyType> iter = list.GetEnumerator();

while (iter.MoveNext())

{

Console.WriteLine(iter.Current);

}

// 'неявная' версия

foreach (MyType value in list)

{

Console.WriteLine(value);

}

Page 173: ук 03.003.01 2011

• Внешние и внутренние – Внешние рассмотрены выше

– Внутренние AdsGrid grid = new AdsGrid();

grid.MoveToFirst();

while(grid.IsLast())

{

doSomething(grid.Current());

}

Закладки – обеспечение нескольких активных просмотров одновременно

AdsGrid grid = new AdsGrid();

grid.MoveToFirst();

while(!grid.IsLast())

{

Log(grid);

doSomething(grid.Current());

grid.MoveToNext();

}

Page 174: ук 03.003.01 2011

void Log(AdsGrid grid)

{

grid.MoveToFirst();

while (!grid.IsLast())

{

LogOneRecord(grid.Current());

grid.MoveToNext();

}

}

Решение class Bookmark: IDisposable

{

private GridCursor old;

private AdsGrid grid;

public Bookmark(AdsGrid grid)

{

old = grid.Current();

this.grid = grid;

}

public void Dispose()

{

grid.SetCursor(old);

}

}

Page 175: ук 03.003.01 2011

AdsGrid grid = new AdsGrid();

using (Bookmark bookmark = new Bookmark(grid))

{

grid.MoveToFirst();

while(!grid.IsLast())

{

Log(grid);

doSomething(grid.Current());

grid.MoveToNext();

}

}

void Log(AdsGrid grid)

{

using (Bookmark bookmark = new Bookmark(grid))

{

grid.MoveToFirst();

while (!grid.IsLast())

{

LogOneRecord(grid.Current());

grid.MoveToNext();

}

}

}

Page 176: ук 03.003.01 2011

• Набор методов итератора – Для чтения public T Current

{

get;

}

– Для записи public T Current

{

get;

}

– Односторонний public bool MoveNext();

– Двусторонний public bool MovePrevious();

– С произвольным доступом public T this[int index]

{

get;

}

Page 177: ук 03.003.01 2011

• Полиморфные итераторы

• Устойчивость итератора к изменениям контейнера

• Доступ ко внутреннему представлению контейнера

• Итераторы и составные объекты – Несколько уровней вложенности

– Несколько способов обхода

• Пустые итераторы Могут применяться вместе паттерном компоновщик для листовых

элементов древовидных структур

Page 178: ук 03.003.01 2011

Пример кода

Page 179: ук 03.003.01 2011

Известные применения

• IEnumerator<T> (System.Collections.Generic)

• DbDataReader (System.Data.Common)

• Stream (System.IO)

Page 180: ук 03.003.01 2011

Родственные паттерны

• Часто используются совместно с компоновщиком для составных объектов

• Фабричный метод для создания полиморфных итераторов (GetEnumerator())

• Хранитель для сохранения состояния итератора (Закладка для внутренних итераторов)

Page 181: ук 03.003.01 2011

Состояние

• Категория: паттерн поведения объектов.

• Назначение: Изменение поведения в зависимости от внутреннего состояния объекта.

Page 182: ук 03.003.01 2011

Мотивация

• Объект может пребывать в нескольких состояниях (установка соединения, запущен, приостановлен, запускается, остановлен и т.д.)

• От этих состояний зависит поведение объекта, причем поведение может очень сильно отличаться

• У объекта могут появляться новые состояния, либо меняться переходы между существующими

• Локализуем поведение каждого из состояний внутри отдельного класса.

Page 183: ук 03.003.01 2011

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

• Поведение объекта зависит от состояния, которое должно меняться динамически

• В коде много последовательностей if-else-if, выбор веток которых зависит от состояния объекта

Page 184: ук 03.003.01 2011

Структура

Page 185: ук 03.003.01 2011

Результаты

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

• Явные переходы между состояниями

Побочные эффекты

• Объекты состояния можно разделять (Flyweight)

Page 186: ук 03.003.01 2011

Реализация

• Кто должен определять переход между состояниями

• Таблица переходов между состояниями

• Создание и уничтожение объектов состояния

• Использование динамического наследования

Page 187: ук 03.003.01 2011

Пример кода

Page 188: ук 03.003.01 2011

Известные применения

• WWF

• Windows сервисы

• Потоки

• Сокеты

• Соединения

Page 189: ук 03.003.01 2011

Родственные паттерны

• Приспособленец для разделения объектов состояния

• Состояние часто реализуется в виде одиночки

• Состояние может реализовываться в виде команды или последовательности команд

Page 190: ук 03.003.01 2011

Цепочка ответственности

• Категория: паттерн поведения объектов.

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

Page 191: ук 03.003.01 2011

Мотивация

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

• Поскольку количество объектов нам неизвестно, то должна быть динамическая структура данных, позволяющая хранить в себе все это множество

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

• Чтобы клиент не пришлось перебирать все множество объектов-получателей запроса, нужно предоставить им самим принимать решение – кто будет обрабатывать запрос

Page 192: ук 03.003.01 2011

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

• Есть более одного объекта, способного обработать запрос, причем обработчик заранее неизвестен

• Необходимо отправить запрос одному из нескольких объектов, не указывая, какому именно

• Набор объектов способных обработать запрос, должен задаваться динамически

Page 193: ук 03.003.01 2011

Структура

Page 194: ук 03.003.01 2011
Page 195: ук 03.003.01 2011

Результаты

• ослабление связанности

• дополнительная гибкость при распределении обязанностей

“-”

• получение сообщения не гарантировано

• Замедление работы приложения, в случае, если цепочки будут слишком длинными, а сообщений много

(Qt 4.*)

Page 196: ук 03.003.01 2011

Реализация

• Цепочка приемников – На основе существующих связей (например, ссылки,

используемые Компоновщиком)

– Организация новых связей

• Реализация обработчика по умолчанию

• Представление запросов – Один запрос – функция обработчик

– Много запросов – запрос-объект

• Автоматическое перенаправление запросов (PHP, Javascript)

Page 197: ук 03.003.01 2011

Пример кода

• Ex 04.021.01-2011

Page 198: ук 03.003.01 2011

Известные применения

• GUI, Web-интерфейс

• WWF, WinForms

• ASP .Net MVC, Ruby on Rails, Zend Framework

• Фильтры сообщений

• System.Collections.Concurrent.ConcurrentQueue<T>

• Message Queue

Page 199: ук 03.003.01 2011

Родственные паттерны

• Часто применяется совместно с паттерном компоновщик

• Обработка запросов осуществляется паттерном команда

Page 200: ук 03.003.01 2011

Заместитель

• Категория: паттерн структурирующий объекты.

• Назначение: Является суррогатом другого объекта и контролирует доступ к нему.

• Синоним: Surrogate

Page 201: ук 03.003.01 2011

Мотивация

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

• Разбивать класс на несколько в соответствии с правами доступа – нарушение открыто-замкнутого принципа, кроме того, права могут меняться.

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

Page 202: ук 03.003.01 2011

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

• “Посол”. Локальный представитель вместо объекта находящегося в другом адресном пространстве. (WCF, .Net Remoting)

• “Виртуальный заместитель”. Создает “тяжелые” объекты по требованию. (Например, картинка, отложенные вычисления, ленивая инициализация)

• “Защищающий” заместитель. Контролирует доступ к исходному объекту. (Разграничение прав доступа).

• “Умная ссылка” – Подсчет числа ссылок на реальный объект. Например, копирование

при записи.

– Загрузка объекта в память при первом обращении к нему

– Проверка и установка блокировки на реальный объект при первом обращении к нему

Page 203: ук 03.003.01 2011

Структура

Page 204: ук 03.003.01 2011

Результаты

Зависят от типа Прокси

• Посол скрывает факт удаленности объекта

• Виртуальные заместители выполняют оптимизацию

• Защищающий заместитель и умная ссылка решают дополнительные задачи при доступе к объекту

Page 205: ук 03.003.01 2011

Реализация

• Заместителю не всегда должен быть известен тип реального объекта

• Как обращаться к еще не инстанцированному объекту?

Page 206: ук 03.003.01 2011

Пример кода

• Ex 04.022.01-2011

• Ex 04.023.01-2011

Page 207: ук 03.003.01 2011

Известные применения

• Ссылка на объект в .Net

• WCF, .Net Remoting

Page 208: ук 03.003.01 2011

Родственные паттерны

• Адаптер vs. Заместитель

• Декоратор vs. Заместитель

Page 209: ук 03.003.01 2011

Посетитель

• Категория: паттерн поведения объектов.

• Назначение: Описывает операцию, выполняемую объектом некоторой структуры.

Page 210: ук 03.003.01 2011

Мотивация

• Есть некоторый составной объект, процедура обхода которого достаточно сложна

• Есть несколько операций по данному объекту, которые используют данную процедуру обхода. Необходимо повторно использовать процедуру обхода для выполнения всех операций

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

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

• Раскладываем каждую операцию по методам интерфейса.

Page 211: ук 03.003.01 2011

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

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

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

• Классы объектов структуры меняются редко, а операции над объектами добавляются часто.

Page 212: ук 03.003.01 2011

Структура

Page 213: ук 03.003.01 2011

Результат

• Упрощает добавление новых операций

• Объединяет родственные операции и отсекает те, которые не имеют никакого отношения

• Посещение различных иерархий классов

• Аккумулирование состояния

“-”

• Добавление новых классов затруднено

• Нарушение инкапсуляции

Page 214: ук 03.003.01 2011

Реализация

• Двойная диспетчеризация

• Какой участник несет ответственность за обход структуры

Page 215: ук 03.003.01 2011

Пример кода

• Ex 04.024.01-2011

Page 216: ук 03.003.01 2011

Известные применения

• XML сериализация public class MyClass

{

public MyObject MyObjectProperty;

}

public class MyObject

{

public string ObjectName;

}

<MyClass>

<MyObjectProperty>

<ObjectName>My String</ObjectName>

</MyObjectProperty>

</MyClass>

• XPathNavigator (System.XML.Xpath) XPathDocument document = new XPathDocument("books.xml"); XPathNavigator navigator = document.CreateNavigator(); XPathExpression query = navigator.Compile("/bookstore/book"); XPathNodeIterator nodes = navigator.Select(query); XPathNavigator nodesNavigator = nodes.Current; XPathNodeIterator nodesText = nodesNavigator.SelectDescendants(XPathNodeType.Text, false); while (nodesText.MoveNext())

{ Console.WriteLine(nodesText.Current.Value); }

Page 217: ук 03.003.01 2011

Родственные паттерны

• Компоновщик

• Интерпретатор

Page 218: ук 03.003.01 2011

Паттерн Мост

• Категория: паттерн структурирующий объекты.

• Назначение: Отделить абстракцию от реализации, так чтобы ее можно менять независимо.

• Описание: Handle\Body (Описатель\Тело)

Page 219: ук 03.003.01 2011

Мотивация

• В зависимости от внешних факторов у класса может быть разная реализация

• Разницу в реализации описывать if-else-if нельзя, так нарушит отрыто-замкнутый принцип

• Надо каждую из реализаций представить в виде отдельного класса Implementor

• Для пользователя выбор реализации должен быть прозрачен – значит надо скрыть факт различия реализаций за специальным классом Handle

Page 220: ук 03.003.01 2011

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

• Надо избежать постоянной привязки абстракции к реализации

• И абстракция, и реализация должны расширяться подклассами

• Изменения в реализации абстракции не должны сказываться на клиентах

• Необходимо скрыть от клиентов реализацию абстракции

• Число подклассов в иерархии начинает быстро расти – первый признак, что иерархию классов надо разбить на две.

• Необходимо разделить одну реализацию (объект) между несколькими объектами

Page 221: ук 03.003.01 2011

Структура

Page 222: ук 03.003.01 2011

Результаты

• Отделение интерфейса от реализации

• Повышение степени расширяемости

Побочный эффект

• Сокрытие деталей реализации от клиентов

Page 223: ук 03.003.01 2011

Реализация

• Только один класс Implementor – тогда создавать абстрактный класс необязательно

• Создание правильного класса Implementor – кто определяет?

• Разделение реализаторов

• ВШД 02.021-1997

Page 224: ук 03.003.01 2011

Пример кода

• Ex 04.025.01-2011

Page 225: ук 03.003.01 2011

Известные применения

• Qt 3.*, 4.*

• Темы, скины

Page 226: ук 03.003.01 2011

Родственные паттерны

• Абстрактная фабрика создает экземпляры Implementor

• Adapter vs Мост

• Заместитель vs Мост

• Implementor как Приспособленец

Page 227: ук 03.003.01 2011

Интерпретатор

• Категория: паттерн поведения объектов.

• Назначение: Для заданного языка определяет представление его грамматики, а также интерпретатор предложений данного языка.

Page 228: ук 03.003.01 2011

Мотивация

expression ::= literal | alternation | sequence | repetition | ‘(‘' expression ‘ )’'

alternation : := expression ‘|’' expression

sequence : := expression ‘&’ expression

repetition : := expression ‘*’

literal : := ‘a’ | ‘b’ | ‘c’ | . . . { ‘a’ | 'b' | 'c’ | ... }*

Page 229: ук 03.003.01 2011
Page 230: ук 03.003.01 2011

raining & (dogs | cats) *

Page 231: ук 03.003.01 2011

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

• Грамматика проста.

• Эффективность не главное.

Page 232: ук 03.003.01 2011

Структура

Page 233: ук 03.003.01 2011

Результаты

• Грамматику легко изменять и расширять

• Простая реализация грамматики

• Добавление новых способов интерпретации выражений

Побочный эффект

• Сложные грамматики трудно сопровождать

Page 234: ук 03.003.01 2011

Реализация

• Создание абстрактного синтаксического дерева

• Определение операции Interpret

• Разделение терминальных символов с помощью паттерна приспособленец

Page 235: ук 03.003.01 2011

Пример кода

• Ex 02.026.01-2011

Page 236: ук 03.003.01 2011

Известные применения

• Компоновщик для абстрактного синтаксического дерева

• Интерпретатор может пользоваться итератором для обхода данных

• Посетитель можно использовать для инкапсуляции поведения каждого узла в одном классе

• Приспособленец для разделения терминальных символов