SlideShare a Scribd company logo
1 of 38
Конспект лекций по курсу «Design patterns»
Немчинский Сергей, Luxoft Ukraine 2008

Программа курса
•
•
•
•
•
•
•

История создания
Что такое шаблоны проектирования?
Немного про ООП
Шаблоны GRASP
Шаблоны GoF
Немного о рефакторинге
Лабораторная работа

История создания
В 70-х годах двадцатого века архитектор Кристофер Александр (Christopher Alexander)
составил набор шаблонов проектирования. В области архитектуры эта идея не получила
такого развития, как позже в области программной разработки.
В 1987 году Кент Бэк (Kent Beck) и Вард Каннигем (Ward Cunningham) взяли идеи
Кристофер Александра и разработали шаблоны применительно к разработке
программного обеспечения для разработки графических оболочек на языке Smalltalk.
В 1988 году Эрих Гамма (Erich Gamma) начал писать докторскую работу при цюрихском
университете об общей переносимости этой методики на разработку программ.
В 1989—1991 годах Джеймс Коплин (James Coplien) трудился над разработкой идиом для
программирования на C++ и опубликовал в 1991 году книгу Advanced C++ Idioms.
В этом же году Эрих Гамма заканчивает свою докторскую работу и переезжает в США,
где в сотрудничестве с Ричардом Хелмом (Richard Helm), Ральфом Джонсоном (Ralph
Johnson) и Джоном Влиссидсом (John Vlissides) публикует книгу Design Patterns —
Elements of Reusable Object-Oriented Software.
В этой книге описаны 23 шаблона проектирования. Также команда авторов этой книги
известна общественности под названием «Банда четырёх» (англ. Gang of Four, часто
сокращается до «GoF»). Именно эта книга стала причиной роста популярности шаблонов
проектирования.

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

Idiom
o Напрямую связана с языком программирования
Specific design
o Решение частной задачи
Standard design
o Дополнительный уровень абстракции
1
•

Design pattern
o Объектно-ориентированные шаблоны – отношения, взаимодействие и
распределение ответственности между классами или объектами для всего
класса задач

Что такое шаблоны проектирования?
"Каждый паттерн описывает некую повторяющуюся проблему и ключ к ее разгадке,
причем таким образом, что этим ключом можно пользоваться при решении самых
разнообразных задач". Christopher Alexander
Шаблоны проектирования (паттерн, pattern) — это эффективные способы решения
характерных задач проектирования, в частности проектирования компьютерных
программ. Паттерн не является законченным образцом проекта, который может быть
прямо преобразован в код, скорее это описание или образец для того, как решить задачу,
таким образом, чтобы это можно было использовать в различных ситуациях.

Польза





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

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

Итоги
 Шаблоны проектирования (паттерн, pattern) — это эффективные способы решения
характерных задач проектирования;
 Шаблоны - не являются законченным образцом проекта, они лишь способ решения,
«повод подумать»;
 Шаблоны - не панацея, но дают возможность сильно повысить свой уровень
разработчика, использовать лучший опыт;
 Шаблоны – ступенька к становлению Computer Science как науки, а не
ремесленечества.

ООП (Объектно-Ориентированное Программирование)
 парадигма программирования, в которой основной концепцией является понятие
объекта, отождествляя его с объектом предметной области.

2
Основные концепции
 Система состоит из объектов
 Объекты некоторым образом взаимодействуют между собой
 Каждый объект характеризуется своим состоянием и поведением

Принципы ООП
 Инкапсуляция
 Наследование
 Полиморфизм

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

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

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

UML
 UML (сокр. от англ. Unified Modeling Language — унифицированный язык
моделирования) — язык графического описания для объектного моделирования в
области разработки программного обеспечения.
 UML является языком широкого профиля, это открытый стандарт, использующий
графические обозначения для создания абстрактной модели системы, называемой
UML моделью.

3
Виды диаграмм UML
 Structure Diagrams:
 Class diagram
 Component diagram
 Composite structure diagram
 Collaboration (UML2.0)
 Deployment diagram
 Object diagram
 Package diagram
 Behavior Diagrams:
 Activity diagram
 State Machine diagram
 Use case diagram
 Interaction Diagrams:
 Communication diagram
(UML2.0) /
 Collaboration (UML1.x)
 Interaction overview diagram
(UML2.0)
 Sequence diagram
 Timing diagram (UML2.0)

 Структурные диаграммы:
 Классов
 Компонентов
 Композитной/составной
структуры
 Кооперации (UML2.0)
 Развёртывания
 Объектов
 Пакетов
 Диаграммы поведения:
 Деятельности
 Конечных автоматов
(состояний)
 Прецедентов
 Диаграммы взаимодействия:
 Коммуникации (UML2.0) /
 Кооперации (UML1.x)
 Обзора взаимодействия
(UML2.0)
 Последовательности
 Синхронизации (UML2.0)

Диаграмма классов UML
Диаграмма классов, Class Diagram — статическая структурная диаграмма, описывающая
структуру системы, она демонстрирует классы системы, их атрибуты и зависимости
между классами.

Взаимосвязи
 Ассоциация
o Ассоциация представляет семейство связей двух или более классов.
o Существует пять различных типов ассоциации. Наиболее же
распространёнными являются двунаправленная и однонаправленная.
Например, классы рейс и самолёт связаны двунаправленной ассоциацией, а
классы человек и кофейный автомат связаны однонаправленной.
 Агрегация
o Агрегация — «has a» вариант ассоциации.
o встречается, когда один класс является коллекцией или контейнером
других.
4
o время существования содержащихся классов не зависит от времени
существования содержащего их класса. Если контейнер будет уничтожен, то
его содержимое — нет.

 Композиция
o Композиция — более строгий вариант «has a» ассоциации (отношение –
«состоит из»)
o Композиция имеет жёсткую зависимость времени существования
экземпляров класса контейнера и экземпляров содержащихся классов. Если
контейнер будет уничтожен, то всё его содержимое будет уничтожено
также.
o Графически представляется как и агрегация, но с закрашенным ромбиком.
 Генерализация (обобщение)
o Генерализация показывает, что один из двух связанных классов (подтип)
является более частной формой другого (надтипа), который называется
обобщением первого.
o Графически генерализация представляется линией с пустым треугольником
у супертипа
o Генерализация также известна как наследование или «is a» взаимосвязь.

 Реализация
o Реализация — отношение между двумя элементами модели, в котором один
элемент (клиент) реализует поведение, заданное другим (поставщиком).
o Графически реализация представляется также как и генерализация, но с
пунктирной линией.

5
GRASP
 Craig Larman
 Книга Applying UML and Patterns, 3ed. GRASP stands for General Responsibility
Assignment Software Patterns.

Полный список шаблонов GRASP










Information Expert
Creator
Controller
Low Coupling
High Cohesion
Polymorphism
Pure Fabrication
Indirection
Protected Variations

6
Шаблон информационный эксперт (Information Expert)- GRASP
 Проблема
o В системе должна аккумулироваться, рассчитываться и т. п. необходимая
информация.
 Решение
o Назначить обязанность аккумуляции информации, расчета и т. п. некоему
классу (информационному эксперту), обладающему необходимой
информацией.
 Рекомендации
o Информационным экспертом может быть не один класс, а несколько.
 Пример
o Необходимо рассчитать общую сумму продажи. Имеются классы
проектирования "Продажа", "ТоварПродажа" (продажа отдельного вида
товара в рамках продажи в целом), "ТоварСпецификация" (описание
конкретного вида товара).
o Необходимо распределить обязанности по предоставлению информации и
расчету между этими классами.
o Таким образом, все три объекта являются информационными экспертами.

Создатель экземпляров класса (Creator) – GRASP
 Проблема
o "Кто" должен отвечать за создание экземпляров класса.
 Решение
o Назначить классу В обязанность создавать объекты другого класса А
 Рекомендации
o Логично использовать паттерн если класс В содержит, агрегирует, активно
использует и т.п. объекты класса А.
 Пример
o необходимо определить, какой объект должен отвечать за создание
экземпляра "ТоварПродажа".
7
o Логично, чтобы это был объект "Продажа", поскольку он содержит
(агрегирует) несколько обьектов "ТоварПродажа".

 Преимущества
o Использование этого паттерна не повышает связанности, поскольку
созданный класс, как правило, виден только для класса - создателя.
 Недостатки
o Если процедура создания объекта достаточно сложная (например
выполняется на основе некоего внешнего условия), логично использовать
паттерн "Абстрактная Фабрика",, то есть, делегировать обязанность
создания объектов специальному классу.

Контроллер (Controller) – GRASP
 Проблема
o "Кто" должен отвечать за обработку входных системных событий?
 Решение
o Обязанности по обработке системных сообщений делегируются
специальному классу. Контроллер - это объект, который отвечает за
обработку системных событий и не относится к интерфейсу пользователя.
Контроллер определяет методы для выполнения системных операций.
 Рекомендации
o Для различных прецедентов логично использовать разные контроллеры
(контроллеры прецедентов) - контроллеры не должны быть перегружены.
Внешний контроллер представляет всю систему целиком, его можно
использовать, если он будет не слишком перегруженным (то есть, если
существует лишь несколько системных событий).
 Преимущества
o Удобно накапливать информацию о системных событиях (в случае, если
системные операции выполняются в некоторой определенной
последовательности).
o Улучшаются условия для повторного использования компонентов
(системные события обрабатываются Контроллером а не элементами
интерфейса пользователя).
 Недостатки
8
o Контроллер может оказаться перегружен.

Низкая связанность (Low Coupling)
 Проблема
o Обеспечить низкую связанность при создании экземпляра класса и
связывании его с другим классом.
 Решение
o Распределить обязанности между объектами так, чтобы степень связанности
оставалась низкой.

Высокое зацепление (High Cohesion) – GRASP
 Проблема
o Необходимо обеспечить выполнение объектами разнородных функций.
 Решение
o Обеспечить распределение обязанностей с высоким зацеплением.
 Преимущества
o Классы с высокой степенью зацепления просты в поддержке и повторном
использовании.
 Недостатки
o Иногда бывает неоправданно использовать высокое зацепление для
распределенных серверных объектов. В этом случае для обеспечения
быстродействия необходимо создать несколько более крупных серверных
объектов со слабым зацеплением.

Полиморфизм (Polymorphism) – GRASP
 Проблема
9
o Как обрабатывать альтернативные варианты поведения на основе типа?
o Как заменять подключаемые компоненты системы?
 Решение
o Обязанности распределяются для различных вариантов поведения с
помощью полиморфных операций для этого класса.
o Каждая внешняя система имеет свой интерфейс.

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

Искусственный (Pure Fabrication) – GRASP
 Проблема
o Какой класс должен обеспечивать реализацию паттернов "Высокое
зацепление", и "Низкая связанность"?
 Решение
o Присвоить группу обязанностей с высокой степенью зацепления классу,
который не представляет конкретного понятия из предметной области
(синтезировать искусственную сущность для обеспечения высокого
зацепления и слабого связывания).
 Пример
o Какой класс должен сохранять экземпляры класса "Продажа" в реляционной
базе данных?
o Если возложить эту обязанность на класс "Продажа", то будем иметь
низкую степень зацепления и высокую степень связывания (поскольку класс
"Продажа" должен быть связан с интерфейсом реляционной базы данных.
o Хранение объектов в реляционной базе данных - это общая задача, которую
придется решать для многих классов.

10
o Решением данной проблемы будет создание нового класса
"ПостоянноеХранилище", ответственного за сохранение обьектов
некоторого вида в базе данных.

 Преимущества
o Класс "ПостоянноеХранилище" будет обладать низкой степенью
связывания и высокой степенью зацепления.
 Недостатки
o Данным паттерном не следует злоупотреблять иначе все функции системы
превратятся в объекты.

Перенаправление (Indirection) – GRASP
 Проблема
o Как перераспределить обязанности обьектов, чтобы обеспечить отсутствие
прямого связывания?
 Решение
o Присвоить обязанности по обеспечению связи между службами или
компонентами промежуточному объекту.
 Пример
o См. пример к паттерну "Искусственный". Класс "Хранилище" выступает в
роли промежуточного звена между классом "Продажа" и базой данных.

Устойчивый к изменениям (Protected Variations) – GRASP
 Проблема
o Как спроектировать систему так, чтобы изменение одних ее элементов не
влияло на другие?
 Решение
o Идентифицировать точки возможных изменений или неустойчивости и
распределить обязанности таким образом, чтобы обеспечить устойчивую
работу системы.

11
Анти-паттерны
Анти-паттерны (anti-patterns), также известные как ловушки (pitfalls) — это классы
наиболее часто внедряемых плохих решений проблем. Они изучаются, как категория, в
случае когда их хотят избежать в будущем, и некоторые отдельные случаи их могут
быть распознаны при изучении неработающих систем.

Анти-паттерны в объектно-ориентированном
программировании
 Базовый класс-утилита (BaseBean): Наследование функциональности из классаутилиты вместо делегирования к нему
 Вызов предка (CallSuper): Для реализации прикладной функциональности методу
класса-потомка требуется в обязательном порядке вызывать те же методы классапредка.
 Ошибка пустого подкласса (Empty subclass failure): Создание класса, который не
проходит «проверку пустоты подкласса» («Empty Subclass Test») из-за различного
поведения по сравнению с классом, который наследуется от него без изменений
 Божественный объект (God object): Концентрация слишком большого количества
функций в одиночной части дизайна (классе)
 Объектная клоака (Object cesspool): Переиспользование объектов, чьё состояние не
удовлетворяет (возможно неявному) контракту переиспользования.
 Полтергейст (компьютер) (Poltergeist): Объекты, чьё единственное предназначение
— передавать информацию другим объектам
 Проблема йо-йо (Yo-yo problem): Структура (например: наследования) которая
тяжело понятна вследствие избыточной фрагментации
 Синглетонизм (Singletonitis): Избыточное использование паттерна синглетон

Анти-паттерны в программировании
 Ненужная сложность (Accidental complexity): Внесение ненужной сложности в
решение

12
 Действие на расстоянии (Action at a distance): Неожиданное взаимодействие между
широко разделёнными частями системы
 Накопить и запустить (Accumulate and fire): Установка параметров подпрограмм в
наборе глобальных переменных
 Слепая вера (Blind faith): Недостаточная проверка (a) корректности исправления
ошибки или (b) результата работы подпрограммы
 Лодочный якорь (Boat anchor): Сохранение более не используемой части системы
 Активное ожидание (Busy spin): Потребление ресурсов ЦПУ (процессорного
времени) во время ожидания события, обычно при помощи постоянно повторяемой
проверки, вместо того, чтобы использовать систему сообщений
 Кэшированный сбой (Caching failure): Забывать сбросить флаг ошибки после её
обработки
 Проверка типа вместо интерфейса (Checking type instead of membership, Checking
type instead of interface): Проверка того, что объект имеет специфический тип в то
время, когда требуется только определённый интерфейс
 Инерция кода (Code momentum): Сверхограничение части системы путём
постоянного подразумевания её поведения в других частях системы
 Кодирование путём исключения (Coding by exception): Добавление нового кода для
поддержки каждого специального распознанного случая
 Таинственный код (Cryptic code): Использование аббревиатур вместо полных
(самоописывающих) имён
 Блокировка с двойной проверкой (Double-checked locking): Проверка перед
блокировкой может выйти из строя в случае использования современного
аппаратного обеспечения или компиляторов
 Жёсткое кодирование (Hard code): Внедрение предположений об окружении
системы в слишком большом количестве точек её реализации
 Магические числа (Magic numbers): Включение чисел в алгоритмы без объяснений
 Процедурный код (Procedural code): Когда другая парадигма является более
подходящей
 Спагетти-код (Spaghetti code): Системы, чья структура редко понятна, особенно
потому что структура кода используется неправильно
 Мыльный пузырь (Soap bubble): Класс, инициализированый мусором, максимально
долго притворяется, что содержит какие-то данные.

Методологические анти-паттерны
 Программирование методом копирования-вставки (Copy and paste programming):
Копирование (и лёгкая модификация) существующего кода вместо создания общих
решений
 Дефакторинг (De-Factoring): Процесс уничтожения функциональности и замены её
документацией
 Золотой молот (Golden hammer): Сильная уверенность в том, что любимое решение
универсально применимо
 Фактор невероятности (Improbability factor): Предположение о невозможности
того, что сработает известная ошибка
 Преждевременная оптимизация (Premature optimization): Оптимизация на основе
недостаточной информации
 Изобретение колеса (Reinventing the wheel): Ошибка адаптации существующего
решения

13
 Изобретение квадратного колеса (Reinventing the square wheel): Создание плохого
решения, когда существует хорошее

Шаблоны GoF
Типы шаблонов
 Порождающие паттерны проектирования
 Структурные паттерны проектирования классов/объектов
 Паттерны проектирования поведения классов/объектов

Порождающие паттерны (Creational Patterns)






Абстрактная фабрика (Abstract Factory, Factory), др. название Инструментарий (Kit)
Одиночка (Singleton)
Прототип (Prototype)
Строитель (Builder)
Фабричный метод (Factory Method) или Виртуальный конструктор (Virtual
Constructor)

Абстрактная фабрика (Abstract Factory, Factory)
 Проблема
o Создать семейство взаимосвязанных или взаимозависимых объектов (не
специфицируя их конкретных классов).
 Решение
o Создать абстрактный класс, в котором объявлен интерфейс для создания
конкретных классов.

14
/*
* GUIFactory example
*/
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Button
{
public:
virtual ~Button() { }
virtual void paint() = 0;
};
class WinButton : public Button
{
public:
void paint()
{
cout<<"I'm a WinButton: ";
}
};
class OSXButton : public Button
{
public:
void paint()
{
15
cout<<"I'm an OSXButton: ";
}
};
class GUIFactory
{
public:
virtual ~GUIFactory() { }
virtual Button* createButton() = 0;
static GUIFactory* getFactory();
};
class WinFactory : public GUIFactory
{
public:
Button* createButton()
{
return new WinButton();
}
};
class OSXFactory : public GUIFactory
{
public:
Button* createButton()
{
return new OSXButton();
}
};
int main()
{
GUIFactory* factory = GUIFactory::getFactory();
Button* button = factory->createButton();
button->paint();
delete factory;
delete button;
return 0;
}
// Output is either:
//
"I'm a WinButton:"
// or:
//
"I'm an OSXButton:"
 Преимущества
o Изолирует конкретные классы. Поскольку "Абстрактная фабрика"
инкапсулирует ответственность за создание классов и сам процесс их
создания, то она изолирует клиента от деталей реализации классов.
o Упрощена замена "Абстрактной фабрики", поскольку она используется в
приложении только один раз при инстанцировании.
 Недостатки
16
o Интерфейс "Абстрактной фабрики" фиксирует набор объектов, которые
можно создать. Расширение "Абстрактной фабрики" для изготовления
новых объектов часто затруднительно.

Фабричный метод (Factory Method ) или Виртуальный
конструктор (Virtual Constructor)
 Проблема
o Определить интерфейс для создания объекта, но оставить подклассам
решение о том, какой класс инстанцировать, то есть, делегировать
инстанцирование подклассам.
 Используется, когда:
o классу заранее неизвестно, объекты каких подклассов ему нужно создавать.
o класс спроектирован так, чтобы объекты, которые он создаёт,
специфицировались подклассами.
o класс делегирует свои обязанности одному из нескольких вспомогательных
подклассов, и планируется локализовать знание о том, какой класс
принимает эти обязанности на себя.
 Решение
o Абстрактный класс "Создатель" объявляет ФабричныйМетод,
возвращающий объект типа "Продукт" (абстрактный класс, определяющий
интерфейс обьектов, создаваемых фабричным методом).
o "Создатель также может определить реализацию по умолчанию
ФабричногоМетода, который возвращает "КонкретныйПродукт".
"КонкретныйСоздатель" замещает ФабричныйМетод, возвращающий
объект "КонкретныйПродукт".
o "Создатель" "полагается" на свои подклассы в определении
ФабричногоМетода, возвращающего объект "КонкретныйПродукт"

class Computer
{
public:
virtual void Run() = 0;
virtual void Stop() = 0;
};
class Laptop: public Computer
{
17
public:
virtual void Run(){mHibernating = false;}
virtual void Stop(){mHibernating = true;}
private:
bool mHibernating; // Whether or not the machine is
hibernating
};
class Desktop: public Computer
{
public:
virtual void Run(){mOn = true;}
virtual void Stop(){mOn = false;}
private:
bool mOn; // Whether or not the machine has been turned
on
};
class ComputerFactory
{
public:
static Computer *NewComputer(const std::string
&description)
{
if(description == "laptop")
return new Laptop;
if(description == "desktop")
return new Desktop;
return NULL;
}
};
 Преимущества
o Избавляет проектировщика от необходимости встраивать в код зависящие
от приложения классы.
 Недостатки
o Возникает дополнительный уровень подклассов.

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

Адаптер (Adapter)
Декоратор (Decorator) или Оболочка (Wrapper)
Заместитель (Proxy) или Суррогат (Surrogate)
Компоновщик (Composite)
Мост (Bridge), Handle (описатель) или Тело (Body)
Приспособленец (Flyweight)
Фасад (Facade)

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

// Purpose. Adapter design pattern demo
//
// Discussion. LegacyRectangle's interface is not compatible
with the
// system that would like to reuse it. An abstract base class
is created
// that specifies the desired interface. An "adapter" class is
defined
// that publicly inherits the interface of the abstract class,
and
// privately inherits the implementation of the legacy
component. This
19
// adapter class "maps" or "impedance matches" the new interface
to the
// old implementation.
#include <iostream.h>
typedef int Coordinate;
typedef int Dimension;
/////////////////////////// Desired
interface ///////////////////////////
class Rectangle {
public:
virtual void draw() = 0;
};
/////////////////////////// Legacy
component ///////////////////////////
class LegacyRectangle {
public:
LegacyRectangle( Coordinate x1, Coordinate y1,
Coordinate x2, Coordinate y2 ) {
x1_ = x1; y1_ = y1; x2_ = x2; y2_ = y2;
cout << "LegacyRectangle: create. (" << x1_ << "," <<
y1_
<< ") => (" << x2_ << "," << y2_ << ")" << endl; }
void oldDraw() {
cout << "LegacyRectangle: oldDraw. (" << x1_ << "," <<
y1_
<< ") => (" << x2_ << "," << y2_ << ")" << endl; }
private:
Coordinate x1_;
Coordinate y1_;
Coordinate x2_;
Coordinate y2_;
};
/////////////////////////// Adapter
wrapper ///////////////////////////
class RectangleAdapter : public Rectangle, private
LegacyRectangle {
public:
RectangleAdapter( Coordinate x, Coordinate y, Dimension w,
Dimension h )
: LegacyRectangle( x, y, x+w, y+h ) {
cout << "RectangleAdapter: create. (" << x << "," << y
<< "), width = " << w << ", height = " << h << endl; }
virtual void draw() {
cout << "RectangleAdapter: draw." << endl;
oldDraw(); }
};
20
void main() {
Rectangle*
r->draw();
}
//
//
//
//

r = new RectangleAdapter( 120, 200, 60, 40 );

LegacyRectangle:
RectangleAdapter:
RectangleAdapter:
LegacyRectangle:

create. (120,200) => (180,240)
create. (120,200), width = 60, height = 40
draw.
oldDraw. (120,200) => (180,240)

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

Декоратор (Decorator) или Оболочка (Wrapper)
 Проблема
o Возложить дополнительные обязанности (прозрачные для клиентов) на
отдельный объект, а не на класс в целом.
 Рекомендации
o Применение нескольких "Декораторов" к одному "Компоненту" позволяет
произвольным образом сочетать обязанности, например, одно свойство
можно добавить дважды.
 Решение
o Динамически добавить объекту новые обязанности не прибегая при этом к
порождению подклассов (наследованию).
o "Компонент"определяет интерфейс для обьектов, на которые могут быть
динамически возложены дополнительные обязанности,
"КонкретныйКомпонент" определяет объект, на который возлагаются
дополнительные обязанности, "Декоратор" - хранит ссылку на объект
"Компонент" и определяет интерфейс, соответствующий интерфейсу
"Компонента". "КонкретныйДекоратор" возлагает дополнительные
обязанности на компонент.
o "Декоратор" переадресует запросы объекту "Компонент".

21
#include <iostream>
using namespace std;
/* Component (interface) */
class Widget {
public:
virtual void draw() = 0;
};
/* ConcreteComponent */
class TextField : public Widget {
private:
int width, height;
public:
TextField( int w, int h ){
width = w;
height = h;
}
void draw() {
cout << "TextField: " << width << ", " << height << 'n';
}
};
/* Decoder (interface)*/
class Decorator : public Widget {
22
private:
Widget* wid;

// reference to Widget

public:
Decorator( Widget* w )
wid = w;
}

{

void draw() {
wid->draw();
}
};
/* ConcreteDecoderA */
class BorderDecorator : public Decorator {
public:
BorderDecorator( Widget* w ) : Decorator( w ) { }
void draw() {
Decorator::draw();
cout << "
BorderDecorator" << 'n';
}
};
/* ConcreteDecoderB */
class ScrollDecorator : public Decorator {
public:
ScrollDecorator( Widget* w ) : Decorator( w ) { }
void draw() {
Decorator::draw();
cout << "
ScrollDecorator" << 'n';
}
};
void main( void ) {
Widget* aWidget = new BorderDecorator(
new BorderDecorator(
new ScrollDecorator(
new TextField( 80, 24 ))));
aWidget->draw();
}
 Преимущества
o Большая гибкость, чем у статического наследования: можно добавлять и
удалять обязанности во время выполнения программы в то время как при
использовании наследования надо было бы создавать новый класс для
каждой дополнительной обязанности.
o Данный паттерн позволяет избежать перегруженных методами классов на
верхних уровнях иерархии - новые обязанности можно добавлять по мере
необходимости.
23
 Недостатки
o "Декоратор" и его "Компонент" не идентичны, и, кроме того, получается,
что система состоит из большого числа мелких объектов, которые похожи
друг на друга и различаются только способом взаимосвязи, а не классом и
не значениями своих внутренних переменных - такая система сложна в
изучении и отладке.

Компоновщик (Composite)
 Проблема
o Как обрабатывать группу или композицию структур объектов
одновременно?
 Решение
o Определить классы для композитных и атомарных объектов таким образом,
чтобы они реализовывали один и тот же интерфейс.

// file graphic.h starting here #include <iostream.h>
class Composite;
class Graphic {
friend class Composite;
Graphic *next;
virtual int pictureDetect(){return(O);}
public:
virtual void draw(){}
Graphic(){next=NULL;}
};
class Line : public Graphic {
int xl,yl,x2,y2;
public:
virtual void draw(void)
{cout<<"Line:"<<xl<<yl<<x2<<y2<<'n';)
Line(int Xl,int Yl,int X2,int Y2){xl=X1; yl=Y1; x2=X2;
y2=Y2;}
24
};
class Text : public Graphic {
int x,y;
char *text;
public:
virtual void draw(void){cout<<"Text:g <<X<<y<<
text<<'n';}
Text(int X,int Y. char *tx){x=X; y=Y; text=tx;}
};
class Picture : public Graphic {
friend class Composite;
Graphic *first;
virtual int pictureDetect(){return(1);}
public:
virtual void draw(void){cout<<"Picture:nN;}
Picture(){first=NULL;}
class Composite {
public:
void add(Picture *p, Graphic *g){g->next=p->first;
p->first=g;}
void remove(Picture *p, Graphic *g);
void draw(Graphic *g);
void dissolve(Graphic *g);
};
void Composite::remove(Picture *p, Graphic *g){
Graphic *t;
if(p->first==g){p->first=g->next; g->next=NULL;}
else {
for(t=p->first; t; t=t->next) if(t->next==g)break;
if(t){t->next=g->next; g->next=NULL;}
else cout<<"errorn";
}
}
void Composite::draw(Graphic *g){
static int level=O; // not necessary, just for better
// displays
int i;
Graphic *t;
for(i=O;i
level;i++)cout<<"

"; // just to indent the
// print

g->draw();
if(g->pictureDetect()){
level++;
for(t=((Picture *)g)->first; t; t=t->next) draw(t);
level-;
}
}
25
void Composite::dissolve(Graphic *g){
Graphic *t,*tn;
if(g->pictureDetect(){
for(t=((Picture *)g)->first; t; t=tn){
tn=t->next;
t->next=NULL;
}
((Picture *)g)->first=NULL;
}
}
int main(void){
Line *nl,*n2,*n3,*n4; Text *tl,*t2,*t3
Picture *pl,*p2,*p3;
nl=new Line(1,1,11,11); n2=new Line(2,2,22,22);
n3=new Line(3,3,33,33); n4=new Line(4,4,44,44);
tl=new Text(l,l,"one"); t2=new Text(2,2,"two");
t3=new Text(3,3,"three");
pl=new Picture; p2=new Picture; p3=new Picture;
Composite comp;
comp.add(pl,nl); comp.add(pl,n2); comp.add(p2,n3);
comp.add(p2,n4); comp.add(p3,tl); comp.add(p3,t2);
comp.add(p2,t3); comp.add(p2,pl); comp.add(p3,p2);
comp.remove(p2,n4); comp.add(p3,n4);
comp.draw(p3);
comp.dissolve(p2);
cout<<'n'; comp.draw(p3);
return(O);
}

Мост (Bridge), Handle (описатель) или Тело (Body)
 Проблема
o Требуется отделить абстракцию от реализации так, чтобы и то и другое
можно было изменять независимо. При использовании наследования
реализация жестко привязывается к абстракции, что затрудняет
независимую модификацию.
 Решение
o Поместить абстракцию и реализацию в отдельные иерархии классов.

26
using namespace std;
/********************************************/
/* Implementor
*/
/********************************************/
// interface
class DrawingAPI
{
public:
virtual void drawCircle(double x, double y, double radius) = 0;
};
//concrete implementor1
class DrawingAPI1 : public DrawingAPI
{
public:
void drawCircle(double x, double y, double radius)
{
cout<<"API1.circle at"<<x<<":"<<y<<" "<< radius<<endl;
}
};
//concrete implementor2
class DrawingAPI2 : public DrawingAPI
{
public:
void drawCircle(double x, double y, double radius)
{
cout<<"API2.circle at "<<x<<":"<<y<<" "<< radius<<endl;
}
};
27
/**************************************/
/* Abstraction
*/
/**************************************/
class Shape
{
public:
virtual void draw() = 0;
virtual void resizeByPercentage(double pct) = 0;
};
class CircleShape:public Shape
{
public:
CircleShape(double x, double y,double radius,DrawingAPI &drawingAPI):
m_x(x),m_y(y),m_radius(radius),m_drawingAPI(drawingAPI)
{}
void draw()
{
m_drawingAPI.drawCircle(m_x,m_y,m_radius);
}
void resizeByPercentage(double pct)
{
m_radius *= pct;
}
private:
double m_x,m_y,m_radius;
DrawingAPI& m_drawingAPI;
};
////////////////////////////////////////
//Test
typedef std::vector<Shape*>::iterator ShapeIt;
int main(int argc, char* argv[])
{
std::vector<Shape*>
vecShapes;
vecShapes.push_back(new CircleShape(1,2,3,*(new DrawingAPI1)));
vecShapes.push_back(new CircleShape(5,7,11,*(new DrawingAPI2)));
ShapeIt begin,end;
begin = vecShapes.begin();
end = vecShapes.end();
for_each(begin,end,std::bind2nd(std::mem_fun(&Shape::resizeByPercentage),2.5));
for_each(begin,end,mem_fun(&Shape::draw));
return 0;
}
 Преимущества
o Отделение реализации от интерфейса, то есть, "Реализацию" "Абстракции"
можно конфигурировать во время выполнения.
o Разделение классов "Абстракция" и "Реализация" устраняет зависимости от
реализации, устанавливаемые на этапе компиляции: чтобы изменить класс
"Реализация" вовсе не обязательно перекомпилировать класс "Абстракция".
28
Фасад (Facade)
 Проблема
o Как обеспечить унифицированный интерфейс с набором разрозненных
реализаций или интерфейсов, например, с подсистемой, если нежелательно
высокое связывание с этой подсистемой или реализация подсистемы может
измениться?
 Решение
o Определить одну точку взаимодействия с подсистемой - фасадный объект,
обеспечивающий общий интерфейс с подсистемой и возложить на него
обязанность по взаимодействию с ее компонентами.
o Фасад - это внешний объект, обеспечивающий единственную точку входа
для служб подсистемы.
o Реализация других компонентов подсистемы закрыта и не видна внешним
компонентам.
o Фасадный объект обеспечивает реализацию паттерна «Устойчивый к
изменениям» (Protected Variations) с точки зрения защиты от изменений в
реализации подсистемы.

Поведенческие шаблоны (Behavioral)
Интерпретатор (Interpreter)
Итератор (Iterator) или Курсор (Cursor)
Команда (Command), Действие (Action) или Транзакция (Транзакция)
Наблюдатель (Observer), Опубликовать - подписаться (Publish - Subscribe) или
Delegation Event Model
 Посетитель (Visitor)
 Посредник (Mediator)
 Состояние (State)





29





Стратегия (Strategy)
Хранитель (Memento)
Цепочка обязанностей (Chain of Responsibility)
Шаблонный метод (Template Method)

Итератор (Iterator) или Курсор (Cursor)
 Проблема
o Составной объект, например, список, должен предоставлять доступ к своим
элементам (объектам), не раскрывая их внутреннюю структуру, причем
перебирать список требуется по-разному в зависимости от задачи.
• Решение
o Создается класс "Итератор", который определяет интерфейс для доступа и
перебора элементов, "КонкретныйИтератор" реализует интерфейс класса
"Итератор" и следит за текущей позицией при обходе "Агрегата".
o "Агрегат" определяет интерфейс для создания объекта - итератора.
o "КонкретныйАгрегат" реализует интерфейс создания итератора и
возвращает экземпляр класса "КонкретныйИтератор",
"КонкретныйИтератор" отслеживает текущий объект в агрегате и может
вычислить следующий объект при переборе.

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

Команда (Command), Действие (Action) или Транзакция
(Транзакция)
 Проблема

30
 Необходимо послать объекту запрос, не зная о том, выполнение какой
операции запрошено и кто будет получателем.
 Решение
 Инкапсулировать запрос как объект.
 "Клиент" создает объект "КонкретнаяКоманда", который вызывает операции
получателя для выполнения запроса, "Инициатор" отправляет запрос,
выполняя операцию "Команды" Выполнить().
 "Команда" объявляет интерфейс для выполнения операции,
"КонкретнаяКоманда" определяет связь между объектом "Получатель" и
операцией Действие(), и, кроме того, реализует операцию Выполнить()
путем вызова соответствующих операций объекта "Получатель".
 "Клиент" создает экземпляр класса "КонкретнаяКоманда" и устанавливает
его получателя, "Инициатор" обращается к команде для выполнения
запроса, "Получатель" (любой класс) располагает информацией о способах
выполнения операций, необходимых для выполнения запроса.

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

Посетитель (Visitor).
 Проблема
 Над каждым объектом некоторой структуры выполняется операция.
Определить новую операцию, не изменяя классы объектов.
 Решение
• Клиент, использующий данный паттерн, должен создать объект класса
"КонкретныйПосетитель", а затем посетить каждый элемент структуры.
31
•

•
•
•
•

•

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

 Рекомендации
 Логично использовать, если в структуре присутствуют объекты многих
классов с различными интерфейсами, и необходимо выполнить над ними
операции, зависящие от конкретных классов, или если классы,
устанавливающие структуру объектов изменяются редко, но новые
операции над этой структурой добавляются часто.
 Преимущества
 Упрощается добавление новых операций, объединяет родственные
операции в классе "Посетитель".
 Недостатки
32
 Затруднено добавление новых классов "КонкретныйЭлемент", поскольку
требуется объявление новой абстрактной операции в классе "Посетитель".

Состояние (State)
 Проблема
 Варьировать поведение объекта в зависимости от его внутреннего состояния
 Решение
 Класс "Контекст" делегирует зависящие от состояния запросы текущему
объекту "КонкретноеСостояние" (хранит экземпляр подкласса
"КонкретноеСостояние", которым определяется текущее состояние), и
определяет интерфейс, представляющий интерес для клиентов.
 "КонкретноеСостояние" реализует поведение, ассоциированное с неким
состоянием объекта "Контекст". "Состояние" определяет интерфейс для
инкапсуляции поведения, ассоциированного с конкретным экземпляром
"Контекста".

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

Стратегия (Strategy)
 Проблема
 Спроектировать изменяемые, но надежные алгоритмы или стратегии.
 Решение
 Определить для каждого алгоритма или стратегии отдельный класс со
стандартным интерфейсом.
 Пример
 Обеспечение сложной логики вычисления стоимости товаров с учетом
сезонных скидок, скидок постоянным клиентам и т. п. Данная стратегия
может изменяться.
33
 Создается несколько классов "Стратегия", каждый из которых содержит
один и тот же полиморфный метод "ЦенаРассчитать". В качестве
параметров в этот метод передаются данные о продаже. Объект стратегии
связывается с контекстным объектом (тем объектом, к которому
применяется алгоритм).

 Плюсы
 инкапсуляция реализации различных алгоритмов, система становится
независимой от возможных изменений бизнес-правил;
 вызов всех алгоритмов одним стандартным образом;
 отказ от использования переключателей и/или условных операторов.
 Минусы
 создание дополнительных классов

Цепочка обязанностей (Chain of Responsibility)
 Проблема
 Запрос должен быть обработан несколькими объектами.
 Рекомендации
 Логично использовать данный паттерн, если имеется более одного объекта,
способного обработать запрос и обработчик заранее неизвестен (и должен
быть найден автоматически) или если весь набор объектов, которые
способны обработать запрос, должен задаваться автоматически.
 Шаблон рекомендован для использования в условиях:
 в разрабатываемой системе имеется группа объектов, которые могут
обрабатывать сообщения определенного типа;
 все сообщения должны быть обработаны хотя бы одним объектом системы;
 сообщения в системе обрабатываются по схеме «обработай сам либо
перешли другому», то есть одни сообщения обрабатываются на том уровне,
где они получены, а другие пересылаются объектам иного уровня.

34
 Связать объекты - получатели запроса в цепочку и передать запрос вдоль этой
цепочки, пока он не будет обработан.
 "Обработчик" определяет интерфейс для обработки запросов, и, возможно,
реализует связь с преемником,
 Преимущества
 Ослабляется связанность (объект не обязан "знать", кто именно обработает
его запрос).
 Недостатки
 Нет гарантий, что запрос будет обработан, поскольку он не имеет явного
получателя.

Шаблонный метод (Template Method)
 Проблема
 Определить алгоритм и реализовать возможность переопределения
некоторых шагов алгоритма для подклассов (без изменения общей
структуры алгоритма.
 Решение
 "АбстрактныйКласс" определяет абстрактные Операции(), замещаемые в
конкретных подклассах для реализации шагов алгоритма, и реализует
ШаблонныйМетод(), определяющий "скелет" алгоритма.
"КонкретныйКласс" релизует Операции(), выполняющие шаги алгоритма
способом, который зависит от подкласса. "КонкретныйКласс" предполагает,
что инвариантные шаги алгоритма будут выполнены в
"АбстрактномКлассе".

35
Model-view-controller
 Model-view-controller (MVC, «Модель-представление-поведение») — архитектура
программного обеспечения, в которой модель данных приложения,
пользовательский интерфейс и управляющая логика разделены на три отдельных
компонента, так, что модификация одного из компонентов оказывает минимальное
воздействие на другие компоненты.
 Шаблон MVC позволяет разделить данные, представление и обработку действий
пользователя на три отдельных компонента
 Модель (Model). Модель предоставляет данные (обычно для View), а также
реагирует на запросы (обычно от контролера), изменяя свое состояние .
 Представление (View). Отвечает за отображение информации
(пользовательский интерфейс).
 Поведение (Controller). Интерпретирует данные, введенные пользователем,
и информирует модель и представление о необходимости соответствующей
реакции.

36
 Важно отметить, что как представление, так и поведение зависят от модели.
Однако модель не зависит ни от представления, ни от поведения. Это одно из
ключевых достоинств подобного разделения. Оно позволяет строить модель
независимо от визуального представления.
 Впервые данный шаблон проектирования был предложен для языка Smalltalk.

Рефакторинг
 Рефакторинг или Реорганизация — процесс полного или частичного
преобразования внутренней структуры программы при сохранении её внешнего
поведения.
 В его основе лежит последовательность небольших эквивалентных (т.е.,
сохраняющих поведение) преобразований.
 Поскольку каждое преобразование маленькое, программисту легче проследить за
его правильностью, и в то же время, вся последовательность может привести к
существенной перестройке программы и улучшению её согласованности и
четкости.
 Рефакторинг позволяет разрабатывать архитектуру программы постепенно,
откладывая проектные решения до тех пор, пока не станет более ясной их
необходимость.
 Рефакторинг изначально не предназначен для исправления ошибок и добавления
новой функциональности, но помогает избежать ошибок и облегчить добавление
функциональности.
 Наиболее употребимые методы рефакторинга:
 Изменение сигнатуры метода (Change Method Signature)
 Инкапсуляция поля (Encapsulate Field)
 Выделение класса (Extract Class)
 Выделение интерфейса (Extract Interface)
 Выделение локальной переменной (Extract Local Variable)
 Выделение метода (Extract Method)
 Генерализация типа (Generalize Type)
 Встраивание (Inline)
37






Введение фабрики (Introduce Factory)
Введение параметра (Introduce Parameter)
Подъём поля/метода (Pull Up)
Спуск поля/метода (Push Down)
Замена условного оператора полиморфизмом (Replace Conditional with
Polymorphism)

38

More Related Content

What's hot (20)

DDD Strategic Design - Context Maps - Paulo Clavijo - April 2018
DDD Strategic Design - Context Maps - Paulo Clavijo - April 2018DDD Strategic Design - Context Maps - Paulo Clavijo - April 2018
DDD Strategic Design - Context Maps - Paulo Clavijo - April 2018
 
Sequence Diagram
Sequence DiagramSequence Diagram
Sequence Diagram
 
UML diagrams and symbols
UML diagrams and symbolsUML diagrams and symbols
UML diagrams and symbols
 
Paradigma Orientado a Objetos
Paradigma Orientado a ObjetosParadigma Orientado a Objetos
Paradigma Orientado a Objetos
 
Design pattern
Design patternDesign pattern
Design pattern
 
Uml diagrams
Uml diagramsUml diagrams
Uml diagrams
 
Diseño orientado a objeto
Diseño orientado a objetoDiseño orientado a objeto
Diseño orientado a objeto
 
Design patterns
Design patternsDesign patterns
Design patterns
 
Behavioral Design Patterns
Behavioral Design PatternsBehavioral Design Patterns
Behavioral Design Patterns
 
Abstract Factory
Abstract FactoryAbstract Factory
Abstract Factory
 
Diagrama de estado
Diagrama de estadoDiagrama de estado
Diagrama de estado
 
Presentacion Patrones Creacionales
Presentacion Patrones CreacionalesPresentacion Patrones Creacionales
Presentacion Patrones Creacionales
 
Introduction to design patterns
Introduction to design patternsIntroduction to design patterns
Introduction to design patterns
 
Exposición Diagrama de Clases
Exposición Diagrama de ClasesExposición Diagrama de Clases
Exposición Diagrama de Clases
 
Uml clase 04_uml_clases
Uml clase 04_uml_clasesUml clase 04_uml_clases
Uml clase 04_uml_clases
 
Diagramas componentes
Diagramas componentesDiagramas componentes
Diagramas componentes
 
Diagramas UML
Diagramas UMLDiagramas UML
Diagramas UML
 
Design Patterns
Design PatternsDesign Patterns
Design Patterns
 
Uml - An Overview
Uml - An OverviewUml - An Overview
Uml - An Overview
 
DIAGRAMA DE COMPONENTES
DIAGRAMA DE COMPONENTESDIAGRAMA DE COMPONENTES
DIAGRAMA DE COMPONENTES
 

Viewers also liked

Основы Java. ООП. Объекты, классы, интерфейсы
Основы Java. ООП. Объекты, классы, интерфейсыОсновы Java. ООП. Объекты, классы, интерфейсы
Основы Java. ООП. Объекты, классы, интерфейсыSergey Nemchinsky
 
Шаблоны разработки ПО. Рефакторинг
Шаблоны разработки ПО. РефакторингШаблоны разработки ПО. Рефакторинг
Шаблоны разработки ПО. РефакторингSergey Nemchinsky
 
Щаблоны разработки ПО. Антипаттерны
Щаблоны разработки ПО. АнтипаттерныЩаблоны разработки ПО. Антипаттерны
Щаблоны разработки ПО. АнтипаттерныSergey Nemchinsky
 
основы Java переменные, циклы
основы Java   переменные, циклыосновы Java   переменные, циклы
основы Java переменные, циклыSergey Nemchinsky
 
Как найти первую работу и как с нее не вылететь
Как найти первую работу и как с нее не вылететьКак найти первую работу и как с нее не вылететь
Как найти первую работу и как с нее не вылететьSergey Nemchinsky
 
Как пишутся и поддерживаются Enterprise системы
Как пишутся и поддерживаются Enterprise системыКак пишутся и поддерживаются Enterprise системы
Как пишутся и поддерживаются Enterprise системыSergey Nemchinsky
 

Viewers also liked (6)

Основы Java. ООП. Объекты, классы, интерфейсы
Основы Java. ООП. Объекты, классы, интерфейсыОсновы Java. ООП. Объекты, классы, интерфейсы
Основы Java. ООП. Объекты, классы, интерфейсы
 
Шаблоны разработки ПО. Рефакторинг
Шаблоны разработки ПО. РефакторингШаблоны разработки ПО. Рефакторинг
Шаблоны разработки ПО. Рефакторинг
 
Щаблоны разработки ПО. Антипаттерны
Щаблоны разработки ПО. АнтипаттерныЩаблоны разработки ПО. Антипаттерны
Щаблоны разработки ПО. Антипаттерны
 
основы Java переменные, циклы
основы Java   переменные, циклыосновы Java   переменные, циклы
основы Java переменные, циклы
 
Как найти первую работу и как с нее не вылететь
Как найти первую работу и как с нее не вылететьКак найти первую работу и как с нее не вылететь
Как найти первую работу и как с нее не вылететь
 
Как пишутся и поддерживаются Enterprise системы
Как пишутся и поддерживаются Enterprise системыКак пишутся и поддерживаются Enterprise системы
Как пишутся и поддерживаются Enterprise системы
 

Similar to Конспект лекций по курсу "Шаблоны разработки ПО"

Общие темы. Тема 02.
Общие темы. Тема 02.Общие темы. Тема 02.
Общие темы. Тема 02.Igor Shkulipa
 
Практический анализ и визуальное моделирование на UML
Практический анализ и визуальное моделирование на UMLПрактический анализ и визуальное моделирование на UML
Практический анализ и визуальное моделирование на UMLNikolai Kireev
 
Сила парадигмы: обзор парадигм программирования
Сила парадигмы: обзор парадигм программированияСила парадигмы: обзор парадигм программирования
Сила парадигмы: обзор парадигм программированияVasiliy Sabadazh
 
ВИРТУАЛЬНАЯ ЛАБОРАТОРИЯ ОБУЧЕНИЯ МЕТОДАМ ИСКУССТВЕННОГО ИНТЕЛЛЕКТА ДЛЯ ГЕНЕРА...
ВИРТУАЛЬНАЯ ЛАБОРАТОРИЯ ОБУЧЕНИЯ МЕТОДАМ ИСКУССТВЕННОГО ИНТЕЛЛЕКТА ДЛЯ ГЕНЕРА...ВИРТУАЛЬНАЯ ЛАБОРАТОРИЯ ОБУЧЕНИЯ МЕТОДАМ ИСКУССТВЕННОГО ИНТЕЛЛЕКТА ДЛЯ ГЕНЕРА...
ВИРТУАЛЬНАЯ ЛАБОРАТОРИЯ ОБУЧЕНИЯ МЕТОДАМ ИСКУССТВЕННОГО ИНТЕЛЛЕКТА ДЛЯ ГЕНЕРА...ITMO University
 
Бизнес и системный анализ весна 2013 лекция 5
Бизнес и системный анализ весна 2013 лекция 5Бизнес и системный анализ весна 2013 лекция 5
Бизнес и системный анализ весна 2013 лекция 5Technopark
 
C++ осень 2013 лекция 8
C++ осень 2013 лекция 8C++ осень 2013 лекция 8
C++ осень 2013 лекция 8Technopark
 
Парадигма объектно-ориентированного программирования.
Парадигма объектно-ориентированного программирования.Парадигма объектно-ориентированного программирования.
Парадигма объектно-ориентированного программирования.Unguryan Vitaliy
 
C++ осень 2012 лекция 7
C++ осень 2012 лекция 7C++ осень 2012 лекция 7
C++ осень 2012 лекция 7Technopark
 
шаблоны проектирования (42)
шаблоны проектирования (42)шаблоны проектирования (42)
шаблоны проектирования (42)romachka_pole
 
Евгений Кривошеев: Фундаментальные правила и принципы проектирования ПО
Евгений Кривошеев: Фундаментальные правила и принципы проектирования ПОЕвгений Кривошеев: Фундаментальные правила и принципы проектирования ПО
Евгений Кривошеев: Фундаментальные правила и принципы проектирования ПОLuxoft Education Center
 
Классы и объекты в Java
Классы и объекты в JavaКлассы и объекты в Java
Классы и объекты в Javametaform
 
Программирование как способ выражения мыслей.
Программирование как способ выражения мыслей. Программирование как способ выражения мыслей.
Программирование как способ выражения мыслей. Levon Avakyan
 
C# Desktop. Занятие 01.
C# Desktop. Занятие 01.C# Desktop. Занятие 01.
C# Desktop. Занятие 01.Igor Shkulipa
 
Шаблоны проектирования GoF
Шаблоны проектирования GoFШаблоны проектирования GoF
Шаблоны проектирования GoFUnguryan Vitaliy
 

Similar to Конспект лекций по курсу "Шаблоны разработки ПО" (20)

Общие темы. Тема 02.
Общие темы. Тема 02.Общие темы. Тема 02.
Общие темы. Тема 02.
 
Практический анализ и визуальное моделирование на UML
Практический анализ и визуальное моделирование на UMLПрактический анализ и визуальное моделирование на UML
Практический анализ и визуальное моделирование на UML
 
Uml
UmlUml
Uml
 
Сила парадигмы: обзор парадигм программирования
Сила парадигмы: обзор парадигм программированияСила парадигмы: обзор парадигм программирования
Сила парадигмы: обзор парадигм программирования
 
UML: Kinds of Diagram
UML:  Kinds of DiagramUML:  Kinds of Diagram
UML: Kinds of Diagram
 
ВИРТУАЛЬНАЯ ЛАБОРАТОРИЯ ОБУЧЕНИЯ МЕТОДАМ ИСКУССТВЕННОГО ИНТЕЛЛЕКТА ДЛЯ ГЕНЕРА...
ВИРТУАЛЬНАЯ ЛАБОРАТОРИЯ ОБУЧЕНИЯ МЕТОДАМ ИСКУССТВЕННОГО ИНТЕЛЛЕКТА ДЛЯ ГЕНЕРА...ВИРТУАЛЬНАЯ ЛАБОРАТОРИЯ ОБУЧЕНИЯ МЕТОДАМ ИСКУССТВЕННОГО ИНТЕЛЛЕКТА ДЛЯ ГЕНЕРА...
ВИРТУАЛЬНАЯ ЛАБОРАТОРИЯ ОБУЧЕНИЯ МЕТОДАМ ИСКУССТВЕННОГО ИНТЕЛЛЕКТА ДЛЯ ГЕНЕРА...
 
Бизнес и системный анализ весна 2013 лекция 5
Бизнес и системный анализ весна 2013 лекция 5Бизнес и системный анализ весна 2013 лекция 5
Бизнес и системный анализ весна 2013 лекция 5
 
Babich Presentation
Babich PresentationBabich Presentation
Babich Presentation
 
C++ осень 2013 лекция 8
C++ осень 2013 лекция 8C++ осень 2013 лекция 8
C++ осень 2013 лекция 8
 
Составные части объектного подхода
Составные части объектного подходаСоставные части объектного подхода
Составные части объектного подхода
 
Парадигма объектно-ориентированного программирования.
Парадигма объектно-ориентированного программирования.Парадигма объектно-ориентированного программирования.
Парадигма объектно-ориентированного программирования.
 
C++ осень 2012 лекция 7
C++ осень 2012 лекция 7C++ осень 2012 лекция 7
C++ осень 2012 лекция 7
 
шаблоны проектирования (42)
шаблоны проектирования (42)шаблоны проектирования (42)
шаблоны проектирования (42)
 
Нотация UML / UML Notation
Нотация UML / UML NotationНотация UML / UML Notation
Нотация UML / UML Notation
 
Design Rules And Principles
Design Rules And PrinciplesDesign Rules And Principles
Design Rules And Principles
 
Евгений Кривошеев: Фундаментальные правила и принципы проектирования ПО
Евгений Кривошеев: Фундаментальные правила и принципы проектирования ПОЕвгений Кривошеев: Фундаментальные правила и принципы проектирования ПО
Евгений Кривошеев: Фундаментальные правила и принципы проектирования ПО
 
Классы и объекты в Java
Классы и объекты в JavaКлассы и объекты в Java
Классы и объекты в Java
 
Программирование как способ выражения мыслей.
Программирование как способ выражения мыслей. Программирование как способ выражения мыслей.
Программирование как способ выражения мыслей.
 
C# Desktop. Занятие 01.
C# Desktop. Занятие 01.C# Desktop. Занятие 01.
C# Desktop. Занятие 01.
 
Шаблоны проектирования GoF
Шаблоны проектирования GoFШаблоны проектирования GoF
Шаблоны проектирования GoF
 

More from Sergey Nemchinsky

Как найти первую работу и не вылететь с нее
Как найти первую работу  и не вылететь с нееКак найти первую работу  и не вылететь с нее
Как найти первую работу и не вылететь с нееSergey Nemchinsky
 
Быть разработчиком: вызовы, ожидания, перестроение мозгов
Быть разработчиком: вызовы, ожидания, перестроение мозговБыть разработчиком: вызовы, ожидания, перестроение мозгов
Быть разработчиком: вызовы, ожидания, перестроение мозговSergey Nemchinsky
 
Service oriented architecture, Oracle Service Bus
Service oriented architecture, Oracle Service BusService oriented architecture, Oracle Service Bus
Service oriented architecture, Oracle Service BusSergey Nemchinsky
 
Java enterprise: обучение, работа, перспективы
Java enterprise: обучение, работа, перспективыJava enterprise: обучение, работа, перспективы
Java enterprise: обучение, работа, перспективыSergey Nemchinsky
 
Enterprise или на чем стоит мир
Enterprise или на чем стоит мирEnterprise или на чем стоит мир
Enterprise или на чем стоит мирSergey Nemchinsky
 
Java enterprise: Обучение, работа, перспективы
Java enterprise: Обучение, работа, перспективыJava enterprise: Обучение, работа, перспективы
Java enterprise: Обучение, работа, перспективыSergey Nemchinsky
 
Основы Java. 5. Databases
Основы Java. 5. DatabasesОсновы Java. 5. Databases
Основы Java. 5. DatabasesSergey Nemchinsky
 
Основы Java. 4. Collection Framework
Основы Java. 4. Collection FrameworkОсновы Java. 4. Collection Framework
Основы Java. 4. Collection FrameworkSergey Nemchinsky
 
Основы Java. 3. Конструкторы, уровни доступа, статика
Основы Java. 3. Конструкторы, уровни доступа, статикаОсновы Java. 3. Конструкторы, уровни доступа, статика
Основы Java. 3. Конструкторы, уровни доступа, статикаSergey Nemchinsky
 

More from Sergey Nemchinsky (11)

Как найти первую работу и не вылететь с нее
Как найти первую работу  и не вылететь с нееКак найти первую работу  и не вылететь с нее
Как найти первую работу и не вылететь с нее
 
Быть разработчиком: вызовы, ожидания, перестроение мозгов
Быть разработчиком: вызовы, ожидания, перестроение мозговБыть разработчиком: вызовы, ожидания, перестроение мозгов
Быть разработчиком: вызовы, ожидания, перестроение мозгов
 
Service oriented architecture, Oracle Service Bus
Service oriented architecture, Oracle Service BusService oriented architecture, Oracle Service Bus
Service oriented architecture, Oracle Service Bus
 
Java enterprise: обучение, работа, перспективы
Java enterprise: обучение, работа, перспективыJava enterprise: обучение, работа, перспективы
Java enterprise: обучение, работа, перспективы
 
Enterprise или на чем стоит мир
Enterprise или на чем стоит мирEnterprise или на чем стоит мир
Enterprise или на чем стоит мир
 
Java enterprise: Обучение, работа, перспективы
Java enterprise: Обучение, работа, перспективыJava enterprise: Обучение, работа, перспективы
Java enterprise: Обучение, работа, перспективы
 
Основы Java. 5. Databases
Основы Java. 5. DatabasesОсновы Java. 5. Databases
Основы Java. 5. Databases
 
Основы Java. 4. Web
Основы Java. 4. WebОсновы Java. 4. Web
Основы Java. 4. Web
 
Основы Java. 4. Collection Framework
Основы Java. 4. Collection FrameworkОсновы Java. 4. Collection Framework
Основы Java. 4. Collection Framework
 
Основы Java. 3. Конструкторы, уровни доступа, статика
Основы Java. 3. Конструкторы, уровни доступа, статикаОсновы Java. 3. Конструкторы, уровни доступа, статика
Основы Java. 3. Конструкторы, уровни доступа, статика
 
Основы Java. 2. JVM
Основы Java. 2. JVMОсновы Java. 2. JVM
Основы Java. 2. JVM
 

Конспект лекций по курсу "Шаблоны разработки ПО"

  • 1. Конспект лекций по курсу «Design patterns» Немчинский Сергей, Luxoft Ukraine 2008 Программа курса • • • • • • • История создания Что такое шаблоны проектирования? Немного про ООП Шаблоны GRASP Шаблоны GoF Немного о рефакторинге Лабораторная работа История создания В 70-х годах двадцатого века архитектор Кристофер Александр (Christopher Alexander) составил набор шаблонов проектирования. В области архитектуры эта идея не получила такого развития, как позже в области программной разработки. В 1987 году Кент Бэк (Kent Beck) и Вард Каннигем (Ward Cunningham) взяли идеи Кристофер Александра и разработали шаблоны применительно к разработке программного обеспечения для разработки графических оболочек на языке Smalltalk. В 1988 году Эрих Гамма (Erich Gamma) начал писать докторскую работу при цюрихском университете об общей переносимости этой методики на разработку программ. В 1989—1991 годах Джеймс Коплин (James Coplien) трудился над разработкой идиом для программирования на C++ и опубликовал в 1991 году книгу Advanced C++ Idioms. В этом же году Эрих Гамма заканчивает свою докторскую работу и переезжает в США, где в сотрудничестве с Ричардом Хелмом (Richard Helm), Ральфом Джонсоном (Ralph Johnson) и Джоном Влиссидсом (John Vlissides) публикует книгу Design Patterns — Elements of Reusable Object-Oriented Software. В этой книге описаны 23 шаблона проектирования. Также команда авторов этой книги известна общественности под названием «Банда четырёх» (англ. Gang of Four, часто сокращается до «GoF»). Именно эта книга стала причиной роста популярности шаблонов проектирования. Таксономия паттернов • • • Idiom o Напрямую связана с языком программирования Specific design o Решение частной задачи Standard design o Дополнительный уровень абстракции 1
  • 2. • Design pattern o Объектно-ориентированные шаблоны – отношения, взаимодействие и распределение ответственности между классами или объектами для всего класса задач Что такое шаблоны проектирования? "Каждый паттерн описывает некую повторяющуюся проблему и ключ к ее разгадке, причем таким образом, что этим ключом можно пользоваться при решении самых разнообразных задач". Christopher Alexander Шаблоны проектирования (паттерн, pattern) — это эффективные способы решения характерных задач проектирования, в частности проектирования компьютерных программ. Паттерн не является законченным образцом проекта, который может быть прямо преобразован в код, скорее это описание или образец для того, как решить задачу, таким образом, чтобы это можно было использовать в различных ситуациях. Польза     Описывает решение целого класса абстрактных проблем Унификация терминологии, названий модулей и элементов проекта Позволяют, отыскав удачное решение, пользоваться им снова и снова В отличие от идиом, шаблоны независимы от применяемого языка программирования Недостатки  шаблоны могут консервировать громоздкую и малоэффективную систему понятий, разработанную узкой группой  Когда количество шаблонов возрастает, превышая критическую сложность, исполнители начинают игнорировать шаблоны и всю систему, с ними связанную  Есть мнение, что слепое применение шаблонов из справочника, замедляет профессиональный рост программиста, так как подменяет творческую работу механическим подставлением шаблонов. Итоги  Шаблоны проектирования (паттерн, pattern) — это эффективные способы решения характерных задач проектирования;  Шаблоны - не являются законченным образцом проекта, они лишь способ решения, «повод подумать»;  Шаблоны - не панацея, но дают возможность сильно повысить свой уровень разработчика, использовать лучший опыт;  Шаблоны – ступенька к становлению Computer Science как науки, а не ремесленечества. ООП (Объектно-Ориентированное Программирование)  парадигма программирования, в которой основной концепцией является понятие объекта, отождествляя его с объектом предметной области. 2
  • 3. Основные концепции  Система состоит из объектов  Объекты некоторым образом взаимодействуют между собой  Каждый объект характеризуется своим состоянием и поведением Принципы ООП  Инкапсуляция  Наследование  Полиморфизм Инкапсуляция  это принцип, согласно которому любой класс и в более широком смысле – любая часть системы, должны рассматриваться как чёрный ящик — пользователь класса или подсистемы должен видеть и использовать только интерфейс (т. е. список декларируемых свойств и методов) и не вникать во внутреннюю реализацию.  позволяет (теоретически) минимизировать число связей между классами и подсистемами и, соответственно, упростить независимую реализацию и модификацию классов и подсистем. Наследование  возможность порождать один класс от другого с сохранением всех свойств и методов класса-предка (иногда его называют суперклассом) добавляя, при необходимости, новые свойства и методы.  призвано отобразить такое свойство реального мира, как иерархичность. Полиморфизм  классы-потомки могут изменять реализацию метода класса-предка, сохраняя его сигнатуру (таким образом, сохраняя неизменным интерфейс класса-предка).  позволяет обрабатывать объекты классов-потомков как однотипные объекты, не смотря на то, что реализация методов у них может различаться. UML  UML (сокр. от англ. Unified Modeling Language — унифицированный язык моделирования) — язык графического описания для объектного моделирования в области разработки программного обеспечения.  UML является языком широкого профиля, это открытый стандарт, использующий графические обозначения для создания абстрактной модели системы, называемой UML моделью. 3
  • 4. Виды диаграмм UML  Structure Diagrams:  Class diagram  Component diagram  Composite structure diagram  Collaboration (UML2.0)  Deployment diagram  Object diagram  Package diagram  Behavior Diagrams:  Activity diagram  State Machine diagram  Use case diagram  Interaction Diagrams:  Communication diagram (UML2.0) /  Collaboration (UML1.x)  Interaction overview diagram (UML2.0)  Sequence diagram  Timing diagram (UML2.0)  Структурные диаграммы:  Классов  Компонентов  Композитной/составной структуры  Кооперации (UML2.0)  Развёртывания  Объектов  Пакетов  Диаграммы поведения:  Деятельности  Конечных автоматов (состояний)  Прецедентов  Диаграммы взаимодействия:  Коммуникации (UML2.0) /  Кооперации (UML1.x)  Обзора взаимодействия (UML2.0)  Последовательности  Синхронизации (UML2.0) Диаграмма классов UML Диаграмма классов, Class Diagram — статическая структурная диаграмма, описывающая структуру системы, она демонстрирует классы системы, их атрибуты и зависимости между классами. Взаимосвязи  Ассоциация o Ассоциация представляет семейство связей двух или более классов. o Существует пять различных типов ассоциации. Наиболее же распространёнными являются двунаправленная и однонаправленная. Например, классы рейс и самолёт связаны двунаправленной ассоциацией, а классы человек и кофейный автомат связаны однонаправленной.  Агрегация o Агрегация — «has a» вариант ассоциации. o встречается, когда один класс является коллекцией или контейнером других. 4
  • 5. o время существования содержащихся классов не зависит от времени существования содержащего их класса. Если контейнер будет уничтожен, то его содержимое — нет.  Композиция o Композиция — более строгий вариант «has a» ассоциации (отношение – «состоит из») o Композиция имеет жёсткую зависимость времени существования экземпляров класса контейнера и экземпляров содержащихся классов. Если контейнер будет уничтожен, то всё его содержимое будет уничтожено также. o Графически представляется как и агрегация, но с закрашенным ромбиком.  Генерализация (обобщение) o Генерализация показывает, что один из двух связанных классов (подтип) является более частной формой другого (надтипа), который называется обобщением первого. o Графически генерализация представляется линией с пустым треугольником у супертипа o Генерализация также известна как наследование или «is a» взаимосвязь.  Реализация o Реализация — отношение между двумя элементами модели, в котором один элемент (клиент) реализует поведение, заданное другим (поставщиком). o Графически реализация представляется также как и генерализация, но с пунктирной линией. 5
  • 6. GRASP  Craig Larman  Книга Applying UML and Patterns, 3ed. GRASP stands for General Responsibility Assignment Software Patterns. Полный список шаблонов GRASP          Information Expert Creator Controller Low Coupling High Cohesion Polymorphism Pure Fabrication Indirection Protected Variations 6
  • 7. Шаблон информационный эксперт (Information Expert)- GRASP  Проблема o В системе должна аккумулироваться, рассчитываться и т. п. необходимая информация.  Решение o Назначить обязанность аккумуляции информации, расчета и т. п. некоему классу (информационному эксперту), обладающему необходимой информацией.  Рекомендации o Информационным экспертом может быть не один класс, а несколько.  Пример o Необходимо рассчитать общую сумму продажи. Имеются классы проектирования "Продажа", "ТоварПродажа" (продажа отдельного вида товара в рамках продажи в целом), "ТоварСпецификация" (описание конкретного вида товара). o Необходимо распределить обязанности по предоставлению информации и расчету между этими классами. o Таким образом, все три объекта являются информационными экспертами. Создатель экземпляров класса (Creator) – GRASP  Проблема o "Кто" должен отвечать за создание экземпляров класса.  Решение o Назначить классу В обязанность создавать объекты другого класса А  Рекомендации o Логично использовать паттерн если класс В содержит, агрегирует, активно использует и т.п. объекты класса А.  Пример o необходимо определить, какой объект должен отвечать за создание экземпляра "ТоварПродажа". 7
  • 8. o Логично, чтобы это был объект "Продажа", поскольку он содержит (агрегирует) несколько обьектов "ТоварПродажа".  Преимущества o Использование этого паттерна не повышает связанности, поскольку созданный класс, как правило, виден только для класса - создателя.  Недостатки o Если процедура создания объекта достаточно сложная (например выполняется на основе некоего внешнего условия), логично использовать паттерн "Абстрактная Фабрика",, то есть, делегировать обязанность создания объектов специальному классу. Контроллер (Controller) – GRASP  Проблема o "Кто" должен отвечать за обработку входных системных событий?  Решение o Обязанности по обработке системных сообщений делегируются специальному классу. Контроллер - это объект, который отвечает за обработку системных событий и не относится к интерфейсу пользователя. Контроллер определяет методы для выполнения системных операций.  Рекомендации o Для различных прецедентов логично использовать разные контроллеры (контроллеры прецедентов) - контроллеры не должны быть перегружены. Внешний контроллер представляет всю систему целиком, его можно использовать, если он будет не слишком перегруженным (то есть, если существует лишь несколько системных событий).  Преимущества o Удобно накапливать информацию о системных событиях (в случае, если системные операции выполняются в некоторой определенной последовательности). o Улучшаются условия для повторного использования компонентов (системные события обрабатываются Контроллером а не элементами интерфейса пользователя).  Недостатки 8
  • 9. o Контроллер может оказаться перегружен. Низкая связанность (Low Coupling)  Проблема o Обеспечить низкую связанность при создании экземпляра класса и связывании его с другим классом.  Решение o Распределить обязанности между объектами так, чтобы степень связанности оставалась низкой. Высокое зацепление (High Cohesion) – GRASP  Проблема o Необходимо обеспечить выполнение объектами разнородных функций.  Решение o Обеспечить распределение обязанностей с высоким зацеплением.  Преимущества o Классы с высокой степенью зацепления просты в поддержке и повторном использовании.  Недостатки o Иногда бывает неоправданно использовать высокое зацепление для распределенных серверных объектов. В этом случае для обеспечения быстродействия необходимо создать несколько более крупных серверных объектов со слабым зацеплением. Полиморфизм (Polymorphism) – GRASP  Проблема 9
  • 10. o Как обрабатывать альтернативные варианты поведения на основе типа? o Как заменять подключаемые компоненты системы?  Решение o Обязанности распределяются для различных вариантов поведения с помощью полиморфных операций для этого класса. o Каждая внешняя система имеет свой интерфейс.  Преимущества o Впоследствии легко расширять и модернизировать систему.  Недостатки o Не следует злоупотреблять добавлением интерфейсов с применением принципа полиморфизма с целью обеспечения дееспособности системы в неизвестных заранее новых ситуациях. Искусственный (Pure Fabrication) – GRASP  Проблема o Какой класс должен обеспечивать реализацию паттернов "Высокое зацепление", и "Низкая связанность"?  Решение o Присвоить группу обязанностей с высокой степенью зацепления классу, который не представляет конкретного понятия из предметной области (синтезировать искусственную сущность для обеспечения высокого зацепления и слабого связывания).  Пример o Какой класс должен сохранять экземпляры класса "Продажа" в реляционной базе данных? o Если возложить эту обязанность на класс "Продажа", то будем иметь низкую степень зацепления и высокую степень связывания (поскольку класс "Продажа" должен быть связан с интерфейсом реляционной базы данных. o Хранение объектов в реляционной базе данных - это общая задача, которую придется решать для многих классов. 10
  • 11. o Решением данной проблемы будет создание нового класса "ПостоянноеХранилище", ответственного за сохранение обьектов некоторого вида в базе данных.  Преимущества o Класс "ПостоянноеХранилище" будет обладать низкой степенью связывания и высокой степенью зацепления.  Недостатки o Данным паттерном не следует злоупотреблять иначе все функции системы превратятся в объекты. Перенаправление (Indirection) – GRASP  Проблема o Как перераспределить обязанности обьектов, чтобы обеспечить отсутствие прямого связывания?  Решение o Присвоить обязанности по обеспечению связи между службами или компонентами промежуточному объекту.  Пример o См. пример к паттерну "Искусственный". Класс "Хранилище" выступает в роли промежуточного звена между классом "Продажа" и базой данных. Устойчивый к изменениям (Protected Variations) – GRASP  Проблема o Как спроектировать систему так, чтобы изменение одних ее элементов не влияло на другие?  Решение o Идентифицировать точки возможных изменений или неустойчивости и распределить обязанности таким образом, чтобы обеспечить устойчивую работу системы. 11
  • 12. Анти-паттерны Анти-паттерны (anti-patterns), также известные как ловушки (pitfalls) — это классы наиболее часто внедряемых плохих решений проблем. Они изучаются, как категория, в случае когда их хотят избежать в будущем, и некоторые отдельные случаи их могут быть распознаны при изучении неработающих систем. Анти-паттерны в объектно-ориентированном программировании  Базовый класс-утилита (BaseBean): Наследование функциональности из классаутилиты вместо делегирования к нему  Вызов предка (CallSuper): Для реализации прикладной функциональности методу класса-потомка требуется в обязательном порядке вызывать те же методы классапредка.  Ошибка пустого подкласса (Empty subclass failure): Создание класса, который не проходит «проверку пустоты подкласса» («Empty Subclass Test») из-за различного поведения по сравнению с классом, который наследуется от него без изменений  Божественный объект (God object): Концентрация слишком большого количества функций в одиночной части дизайна (классе)  Объектная клоака (Object cesspool): Переиспользование объектов, чьё состояние не удовлетворяет (возможно неявному) контракту переиспользования.  Полтергейст (компьютер) (Poltergeist): Объекты, чьё единственное предназначение — передавать информацию другим объектам  Проблема йо-йо (Yo-yo problem): Структура (например: наследования) которая тяжело понятна вследствие избыточной фрагментации  Синглетонизм (Singletonitis): Избыточное использование паттерна синглетон Анти-паттерны в программировании  Ненужная сложность (Accidental complexity): Внесение ненужной сложности в решение 12
  • 13.  Действие на расстоянии (Action at a distance): Неожиданное взаимодействие между широко разделёнными частями системы  Накопить и запустить (Accumulate and fire): Установка параметров подпрограмм в наборе глобальных переменных  Слепая вера (Blind faith): Недостаточная проверка (a) корректности исправления ошибки или (b) результата работы подпрограммы  Лодочный якорь (Boat anchor): Сохранение более не используемой части системы  Активное ожидание (Busy spin): Потребление ресурсов ЦПУ (процессорного времени) во время ожидания события, обычно при помощи постоянно повторяемой проверки, вместо того, чтобы использовать систему сообщений  Кэшированный сбой (Caching failure): Забывать сбросить флаг ошибки после её обработки  Проверка типа вместо интерфейса (Checking type instead of membership, Checking type instead of interface): Проверка того, что объект имеет специфический тип в то время, когда требуется только определённый интерфейс  Инерция кода (Code momentum): Сверхограничение части системы путём постоянного подразумевания её поведения в других частях системы  Кодирование путём исключения (Coding by exception): Добавление нового кода для поддержки каждого специального распознанного случая  Таинственный код (Cryptic code): Использование аббревиатур вместо полных (самоописывающих) имён  Блокировка с двойной проверкой (Double-checked locking): Проверка перед блокировкой может выйти из строя в случае использования современного аппаратного обеспечения или компиляторов  Жёсткое кодирование (Hard code): Внедрение предположений об окружении системы в слишком большом количестве точек её реализации  Магические числа (Magic numbers): Включение чисел в алгоритмы без объяснений  Процедурный код (Procedural code): Когда другая парадигма является более подходящей  Спагетти-код (Spaghetti code): Системы, чья структура редко понятна, особенно потому что структура кода используется неправильно  Мыльный пузырь (Soap bubble): Класс, инициализированый мусором, максимально долго притворяется, что содержит какие-то данные. Методологические анти-паттерны  Программирование методом копирования-вставки (Copy and paste programming): Копирование (и лёгкая модификация) существующего кода вместо создания общих решений  Дефакторинг (De-Factoring): Процесс уничтожения функциональности и замены её документацией  Золотой молот (Golden hammer): Сильная уверенность в том, что любимое решение универсально применимо  Фактор невероятности (Improbability factor): Предположение о невозможности того, что сработает известная ошибка  Преждевременная оптимизация (Premature optimization): Оптимизация на основе недостаточной информации  Изобретение колеса (Reinventing the wheel): Ошибка адаптации существующего решения 13
  • 14.  Изобретение квадратного колеса (Reinventing the square wheel): Создание плохого решения, когда существует хорошее Шаблоны GoF Типы шаблонов  Порождающие паттерны проектирования  Структурные паттерны проектирования классов/объектов  Паттерны проектирования поведения классов/объектов Порождающие паттерны (Creational Patterns)      Абстрактная фабрика (Abstract Factory, Factory), др. название Инструментарий (Kit) Одиночка (Singleton) Прототип (Prototype) Строитель (Builder) Фабричный метод (Factory Method) или Виртуальный конструктор (Virtual Constructor) Абстрактная фабрика (Abstract Factory, Factory)  Проблема o Создать семейство взаимосвязанных или взаимозависимых объектов (не специфицируя их конкретных классов).  Решение o Создать абстрактный класс, в котором объявлен интерфейс для создания конкретных классов. 14
  • 15. /* * GUIFactory example */ #include <iostream> #include <string> #include <cstdlib> using namespace std; class Button { public: virtual ~Button() { } virtual void paint() = 0; }; class WinButton : public Button { public: void paint() { cout<<"I'm a WinButton: "; } }; class OSXButton : public Button { public: void paint() { 15
  • 16. cout<<"I'm an OSXButton: "; } }; class GUIFactory { public: virtual ~GUIFactory() { } virtual Button* createButton() = 0; static GUIFactory* getFactory(); }; class WinFactory : public GUIFactory { public: Button* createButton() { return new WinButton(); } }; class OSXFactory : public GUIFactory { public: Button* createButton() { return new OSXButton(); } }; int main() { GUIFactory* factory = GUIFactory::getFactory(); Button* button = factory->createButton(); button->paint(); delete factory; delete button; return 0; } // Output is either: // "I'm a WinButton:" // or: // "I'm an OSXButton:"  Преимущества o Изолирует конкретные классы. Поскольку "Абстрактная фабрика" инкапсулирует ответственность за создание классов и сам процесс их создания, то она изолирует клиента от деталей реализации классов. o Упрощена замена "Абстрактной фабрики", поскольку она используется в приложении только один раз при инстанцировании.  Недостатки 16
  • 17. o Интерфейс "Абстрактной фабрики" фиксирует набор объектов, которые можно создать. Расширение "Абстрактной фабрики" для изготовления новых объектов часто затруднительно. Фабричный метод (Factory Method ) или Виртуальный конструктор (Virtual Constructor)  Проблема o Определить интерфейс для создания объекта, но оставить подклассам решение о том, какой класс инстанцировать, то есть, делегировать инстанцирование подклассам.  Используется, когда: o классу заранее неизвестно, объекты каких подклассов ему нужно создавать. o класс спроектирован так, чтобы объекты, которые он создаёт, специфицировались подклассами. o класс делегирует свои обязанности одному из нескольких вспомогательных подклассов, и планируется локализовать знание о том, какой класс принимает эти обязанности на себя.  Решение o Абстрактный класс "Создатель" объявляет ФабричныйМетод, возвращающий объект типа "Продукт" (абстрактный класс, определяющий интерфейс обьектов, создаваемых фабричным методом). o "Создатель также может определить реализацию по умолчанию ФабричногоМетода, который возвращает "КонкретныйПродукт". "КонкретныйСоздатель" замещает ФабричныйМетод, возвращающий объект "КонкретныйПродукт". o "Создатель" "полагается" на свои подклассы в определении ФабричногоМетода, возвращающего объект "КонкретныйПродукт" class Computer { public: virtual void Run() = 0; virtual void Stop() = 0; }; class Laptop: public Computer { 17
  • 18. public: virtual void Run(){mHibernating = false;} virtual void Stop(){mHibernating = true;} private: bool mHibernating; // Whether or not the machine is hibernating }; class Desktop: public Computer { public: virtual void Run(){mOn = true;} virtual void Stop(){mOn = false;} private: bool mOn; // Whether or not the machine has been turned on }; class ComputerFactory { public: static Computer *NewComputer(const std::string &description) { if(description == "laptop") return new Laptop; if(description == "desktop") return new Desktop; return NULL; } };  Преимущества o Избавляет проектировщика от необходимости встраивать в код зависящие от приложения классы.  Недостатки o Возникает дополнительный уровень подклассов. 18
  • 19. Структурные паттерны        Адаптер (Adapter) Декоратор (Decorator) или Оболочка (Wrapper) Заместитель (Proxy) или Суррогат (Surrogate) Компоновщик (Composite) Мост (Bridge), Handle (описатель) или Тело (Body) Приспособленец (Flyweight) Фасад (Facade) Адаптер (Adapter)  Проблема o Необходимо обеспечить взаимодействие несовместимых интерфейсов или как создать единый устойчивый интерфейс для нескольких компонентов с разными интерфейсами.  Решение o Конвертировать исходный интерфейс компонента к другому виду с помощью промежуточного объекта - адаптера, то есть, добавить специальный объект с общим интерфейсом в рамках данного приложения и перенаправить связи от внешних обьектов к этому объекту - адаптеру. // Purpose. Adapter design pattern demo // // Discussion. LegacyRectangle's interface is not compatible with the // system that would like to reuse it. An abstract base class is created // that specifies the desired interface. An "adapter" class is defined // that publicly inherits the interface of the abstract class, and // privately inherits the implementation of the legacy component. This 19
  • 20. // adapter class "maps" or "impedance matches" the new interface to the // old implementation. #include <iostream.h> typedef int Coordinate; typedef int Dimension; /////////////////////////// Desired interface /////////////////////////// class Rectangle { public: virtual void draw() = 0; }; /////////////////////////// Legacy component /////////////////////////// class LegacyRectangle { public: LegacyRectangle( Coordinate x1, Coordinate y1, Coordinate x2, Coordinate y2 ) { x1_ = x1; y1_ = y1; x2_ = x2; y2_ = y2; cout << "LegacyRectangle: create. (" << x1_ << "," << y1_ << ") => (" << x2_ << "," << y2_ << ")" << endl; } void oldDraw() { cout << "LegacyRectangle: oldDraw. (" << x1_ << "," << y1_ << ") => (" << x2_ << "," << y2_ << ")" << endl; } private: Coordinate x1_; Coordinate y1_; Coordinate x2_; Coordinate y2_; }; /////////////////////////// Adapter wrapper /////////////////////////// class RectangleAdapter : public Rectangle, private LegacyRectangle { public: RectangleAdapter( Coordinate x, Coordinate y, Dimension w, Dimension h ) : LegacyRectangle( x, y, x+w, y+h ) { cout << "RectangleAdapter: create. (" << x << "," << y << "), width = " << w << ", height = " << h << endl; } virtual void draw() { cout << "RectangleAdapter: draw." << endl; oldDraw(); } }; 20
  • 21. void main() { Rectangle* r->draw(); } // // // // r = new RectangleAdapter( 120, 200, 60, 40 ); LegacyRectangle: RectangleAdapter: RectangleAdapter: LegacyRectangle: create. (120,200) => (180,240) create. (120,200), width = 60, height = 40 draw. oldDraw. (120,200) => (180,240)  Применяется в случаях o система поддерживает требуемые данные и поведение, но имеет неподходящий интерфейс.  Плюсы o инкапсуляция реализации внешних классов (компонентов, библиотек), система становится независимой от интерфейса внешних классов; o переход на использование других внешних классов не требует переделки самой системы, достаточно реализовать один класс Adapter. Декоратор (Decorator) или Оболочка (Wrapper)  Проблема o Возложить дополнительные обязанности (прозрачные для клиентов) на отдельный объект, а не на класс в целом.  Рекомендации o Применение нескольких "Декораторов" к одному "Компоненту" позволяет произвольным образом сочетать обязанности, например, одно свойство можно добавить дважды.  Решение o Динамически добавить объекту новые обязанности не прибегая при этом к порождению подклассов (наследованию). o "Компонент"определяет интерфейс для обьектов, на которые могут быть динамически возложены дополнительные обязанности, "КонкретныйКомпонент" определяет объект, на который возлагаются дополнительные обязанности, "Декоратор" - хранит ссылку на объект "Компонент" и определяет интерфейс, соответствующий интерфейсу "Компонента". "КонкретныйДекоратор" возлагает дополнительные обязанности на компонент. o "Декоратор" переадресует запросы объекту "Компонент". 21
  • 22. #include <iostream> using namespace std; /* Component (interface) */ class Widget { public: virtual void draw() = 0; }; /* ConcreteComponent */ class TextField : public Widget { private: int width, height; public: TextField( int w, int h ){ width = w; height = h; } void draw() { cout << "TextField: " << width << ", " << height << 'n'; } }; /* Decoder (interface)*/ class Decorator : public Widget { 22
  • 23. private: Widget* wid; // reference to Widget public: Decorator( Widget* w ) wid = w; } { void draw() { wid->draw(); } }; /* ConcreteDecoderA */ class BorderDecorator : public Decorator { public: BorderDecorator( Widget* w ) : Decorator( w ) { } void draw() { Decorator::draw(); cout << " BorderDecorator" << 'n'; } }; /* ConcreteDecoderB */ class ScrollDecorator : public Decorator { public: ScrollDecorator( Widget* w ) : Decorator( w ) { } void draw() { Decorator::draw(); cout << " ScrollDecorator" << 'n'; } }; void main( void ) { Widget* aWidget = new BorderDecorator( new BorderDecorator( new ScrollDecorator( new TextField( 80, 24 )))); aWidget->draw(); }  Преимущества o Большая гибкость, чем у статического наследования: можно добавлять и удалять обязанности во время выполнения программы в то время как при использовании наследования надо было бы создавать новый класс для каждой дополнительной обязанности. o Данный паттерн позволяет избежать перегруженных методами классов на верхних уровнях иерархии - новые обязанности можно добавлять по мере необходимости. 23
  • 24.  Недостатки o "Декоратор" и его "Компонент" не идентичны, и, кроме того, получается, что система состоит из большого числа мелких объектов, которые похожи друг на друга и различаются только способом взаимосвязи, а не классом и не значениями своих внутренних переменных - такая система сложна в изучении и отладке. Компоновщик (Composite)  Проблема o Как обрабатывать группу или композицию структур объектов одновременно?  Решение o Определить классы для композитных и атомарных объектов таким образом, чтобы они реализовывали один и тот же интерфейс. // file graphic.h starting here #include <iostream.h> class Composite; class Graphic { friend class Composite; Graphic *next; virtual int pictureDetect(){return(O);} public: virtual void draw(){} Graphic(){next=NULL;} }; class Line : public Graphic { int xl,yl,x2,y2; public: virtual void draw(void) {cout<<"Line:"<<xl<<yl<<x2<<y2<<'n';) Line(int Xl,int Yl,int X2,int Y2){xl=X1; yl=Y1; x2=X2; y2=Y2;} 24
  • 25. }; class Text : public Graphic { int x,y; char *text; public: virtual void draw(void){cout<<"Text:g <<X<<y<< text<<'n';} Text(int X,int Y. char *tx){x=X; y=Y; text=tx;} }; class Picture : public Graphic { friend class Composite; Graphic *first; virtual int pictureDetect(){return(1);} public: virtual void draw(void){cout<<"Picture:nN;} Picture(){first=NULL;} class Composite { public: void add(Picture *p, Graphic *g){g->next=p->first; p->first=g;} void remove(Picture *p, Graphic *g); void draw(Graphic *g); void dissolve(Graphic *g); }; void Composite::remove(Picture *p, Graphic *g){ Graphic *t; if(p->first==g){p->first=g->next; g->next=NULL;} else { for(t=p->first; t; t=t->next) if(t->next==g)break; if(t){t->next=g->next; g->next=NULL;} else cout<<"errorn"; } } void Composite::draw(Graphic *g){ static int level=O; // not necessary, just for better // displays int i; Graphic *t; for(i=O;i level;i++)cout<<" "; // just to indent the // print g->draw(); if(g->pictureDetect()){ level++; for(t=((Picture *)g)->first; t; t=t->next) draw(t); level-; } } 25
  • 26. void Composite::dissolve(Graphic *g){ Graphic *t,*tn; if(g->pictureDetect(){ for(t=((Picture *)g)->first; t; t=tn){ tn=t->next; t->next=NULL; } ((Picture *)g)->first=NULL; } } int main(void){ Line *nl,*n2,*n3,*n4; Text *tl,*t2,*t3 Picture *pl,*p2,*p3; nl=new Line(1,1,11,11); n2=new Line(2,2,22,22); n3=new Line(3,3,33,33); n4=new Line(4,4,44,44); tl=new Text(l,l,"one"); t2=new Text(2,2,"two"); t3=new Text(3,3,"three"); pl=new Picture; p2=new Picture; p3=new Picture; Composite comp; comp.add(pl,nl); comp.add(pl,n2); comp.add(p2,n3); comp.add(p2,n4); comp.add(p3,tl); comp.add(p3,t2); comp.add(p2,t3); comp.add(p2,pl); comp.add(p3,p2); comp.remove(p2,n4); comp.add(p3,n4); comp.draw(p3); comp.dissolve(p2); cout<<'n'; comp.draw(p3); return(O); } Мост (Bridge), Handle (описатель) или Тело (Body)  Проблема o Требуется отделить абстракцию от реализации так, чтобы и то и другое можно было изменять независимо. При использовании наследования реализация жестко привязывается к абстракции, что затрудняет независимую модификацию.  Решение o Поместить абстракцию и реализацию в отдельные иерархии классов. 26
  • 27. using namespace std; /********************************************/ /* Implementor */ /********************************************/ // interface class DrawingAPI { public: virtual void drawCircle(double x, double y, double radius) = 0; }; //concrete implementor1 class DrawingAPI1 : public DrawingAPI { public: void drawCircle(double x, double y, double radius) { cout<<"API1.circle at"<<x<<":"<<y<<" "<< radius<<endl; } }; //concrete implementor2 class DrawingAPI2 : public DrawingAPI { public: void drawCircle(double x, double y, double radius) { cout<<"API2.circle at "<<x<<":"<<y<<" "<< radius<<endl; } }; 27
  • 28. /**************************************/ /* Abstraction */ /**************************************/ class Shape { public: virtual void draw() = 0; virtual void resizeByPercentage(double pct) = 0; }; class CircleShape:public Shape { public: CircleShape(double x, double y,double radius,DrawingAPI &drawingAPI): m_x(x),m_y(y),m_radius(radius),m_drawingAPI(drawingAPI) {} void draw() { m_drawingAPI.drawCircle(m_x,m_y,m_radius); } void resizeByPercentage(double pct) { m_radius *= pct; } private: double m_x,m_y,m_radius; DrawingAPI& m_drawingAPI; }; //////////////////////////////////////// //Test typedef std::vector<Shape*>::iterator ShapeIt; int main(int argc, char* argv[]) { std::vector<Shape*> vecShapes; vecShapes.push_back(new CircleShape(1,2,3,*(new DrawingAPI1))); vecShapes.push_back(new CircleShape(5,7,11,*(new DrawingAPI2))); ShapeIt begin,end; begin = vecShapes.begin(); end = vecShapes.end(); for_each(begin,end,std::bind2nd(std::mem_fun(&Shape::resizeByPercentage),2.5)); for_each(begin,end,mem_fun(&Shape::draw)); return 0; }  Преимущества o Отделение реализации от интерфейса, то есть, "Реализацию" "Абстракции" можно конфигурировать во время выполнения. o Разделение классов "Абстракция" и "Реализация" устраняет зависимости от реализации, устанавливаемые на этапе компиляции: чтобы изменить класс "Реализация" вовсе не обязательно перекомпилировать класс "Абстракция". 28
  • 29. Фасад (Facade)  Проблема o Как обеспечить унифицированный интерфейс с набором разрозненных реализаций или интерфейсов, например, с подсистемой, если нежелательно высокое связывание с этой подсистемой или реализация подсистемы может измениться?  Решение o Определить одну точку взаимодействия с подсистемой - фасадный объект, обеспечивающий общий интерфейс с подсистемой и возложить на него обязанность по взаимодействию с ее компонентами. o Фасад - это внешний объект, обеспечивающий единственную точку входа для служб подсистемы. o Реализация других компонентов подсистемы закрыта и не видна внешним компонентам. o Фасадный объект обеспечивает реализацию паттерна «Устойчивый к изменениям» (Protected Variations) с точки зрения защиты от изменений в реализации подсистемы. Поведенческие шаблоны (Behavioral) Интерпретатор (Interpreter) Итератор (Iterator) или Курсор (Cursor) Команда (Command), Действие (Action) или Транзакция (Транзакция) Наблюдатель (Observer), Опубликовать - подписаться (Publish - Subscribe) или Delegation Event Model  Посетитель (Visitor)  Посредник (Mediator)  Состояние (State)     29
  • 30.     Стратегия (Strategy) Хранитель (Memento) Цепочка обязанностей (Chain of Responsibility) Шаблонный метод (Template Method) Итератор (Iterator) или Курсор (Cursor)  Проблема o Составной объект, например, список, должен предоставлять доступ к своим элементам (объектам), не раскрывая их внутреннюю структуру, причем перебирать список требуется по-разному в зависимости от задачи. • Решение o Создается класс "Итератор", который определяет интерфейс для доступа и перебора элементов, "КонкретныйИтератор" реализует интерфейс класса "Итератор" и следит за текущей позицией при обходе "Агрегата". o "Агрегат" определяет интерфейс для создания объекта - итератора. o "КонкретныйАгрегат" реализует интерфейс создания итератора и возвращает экземпляр класса "КонкретныйИтератор", "КонкретныйИтератор" отслеживает текущий объект в агрегате и может вычислить следующий объект при переборе.  Преимущества • Поддерживает различные способы перебора агрегата, • одновременно могут быть активны несколько переборов. Команда (Command), Действие (Action) или Транзакция (Транзакция)  Проблема 30
  • 31.  Необходимо послать объекту запрос, не зная о том, выполнение какой операции запрошено и кто будет получателем.  Решение  Инкапсулировать запрос как объект.  "Клиент" создает объект "КонкретнаяКоманда", который вызывает операции получателя для выполнения запроса, "Инициатор" отправляет запрос, выполняя операцию "Команды" Выполнить().  "Команда" объявляет интерфейс для выполнения операции, "КонкретнаяКоманда" определяет связь между объектом "Получатель" и операцией Действие(), и, кроме того, реализует операцию Выполнить() путем вызова соответствующих операций объекта "Получатель".  "Клиент" создает экземпляр класса "КонкретнаяКоманда" и устанавливает его получателя, "Инициатор" обращается к команде для выполнения запроса, "Получатель" (любой класс) располагает информацией о способах выполнения операций, необходимых для выполнения запроса.  Преимущества • Обеспечивает обработку команды в виде объекта, что позволяет сохранять её, передавать в качестве параметра методам, а также возвращать её в виде результата, как и любой другой объект. Посетитель (Visitor).  Проблема  Над каждым объектом некоторой структуры выполняется операция. Определить новую операцию, не изменяя классы объектов.  Решение • Клиент, использующий данный паттерн, должен создать объект класса "КонкретныйПосетитель", а затем посетить каждый элемент структуры. 31
  • 32. • • • • • • "Посетитель" объявляет операцию "Посетить" для каждого класса "КонкретныйЭлемент" (имя и сигнатура данной операции идентифицируют класс, элемент которого посещает "Посетитель" - то есть, посетитель может обращаться к элементу напрямую). "КонкретныйПосетитель" реализует все операции, обьявленные в классе "Посетитель". Каждая операция реализует фрагмент алгоритма, определенного для класса соответствующего объекта в структуре. Класс "КонкретныйПосетитель"предоставляет контекст для этого алгоритма и сохраняет его локальное состояние. "Элемент" определяет операцию "Принять", которая принимает "Посетителя" в качестве аргумента, "КонкретныйЭлемент" реализует операцию "Принять", которая принимает "Посетителя" в качестве аргумента. "СтруктураОбьекта" может перечислить свои аргументы и предоставить посетителю высокоуровневый интерфейс для посещения своих элементов.  Рекомендации  Логично использовать, если в структуре присутствуют объекты многих классов с различными интерфейсами, и необходимо выполнить над ними операции, зависящие от конкретных классов, или если классы, устанавливающие структуру объектов изменяются редко, но новые операции над этой структурой добавляются часто.  Преимущества  Упрощается добавление новых операций, объединяет родственные операции в классе "Посетитель".  Недостатки 32
  • 33.  Затруднено добавление новых классов "КонкретныйЭлемент", поскольку требуется объявление новой абстрактной операции в классе "Посетитель". Состояние (State)  Проблема  Варьировать поведение объекта в зависимости от его внутреннего состояния  Решение  Класс "Контекст" делегирует зависящие от состояния запросы текущему объекту "КонкретноеСостояние" (хранит экземпляр подкласса "КонкретноеСостояние", которым определяется текущее состояние), и определяет интерфейс, представляющий интерес для клиентов.  "КонкретноеСостояние" реализует поведение, ассоциированное с неким состоянием объекта "Контекст". "Состояние" определяет интерфейс для инкапсуляции поведения, ассоциированного с конкретным экземпляром "Контекста".  Преимущества • Локализует зависящее от состояния поведение и делит его на части, соответствующие состояниям, • переходы между состояниями становятся явными. Стратегия (Strategy)  Проблема  Спроектировать изменяемые, но надежные алгоритмы или стратегии.  Решение  Определить для каждого алгоритма или стратегии отдельный класс со стандартным интерфейсом.  Пример  Обеспечение сложной логики вычисления стоимости товаров с учетом сезонных скидок, скидок постоянным клиентам и т. п. Данная стратегия может изменяться. 33
  • 34.  Создается несколько классов "Стратегия", каждый из которых содержит один и тот же полиморфный метод "ЦенаРассчитать". В качестве параметров в этот метод передаются данные о продаже. Объект стратегии связывается с контекстным объектом (тем объектом, к которому применяется алгоритм).  Плюсы  инкапсуляция реализации различных алгоритмов, система становится независимой от возможных изменений бизнес-правил;  вызов всех алгоритмов одним стандартным образом;  отказ от использования переключателей и/или условных операторов.  Минусы  создание дополнительных классов Цепочка обязанностей (Chain of Responsibility)  Проблема  Запрос должен быть обработан несколькими объектами.  Рекомендации  Логично использовать данный паттерн, если имеется более одного объекта, способного обработать запрос и обработчик заранее неизвестен (и должен быть найден автоматически) или если весь набор объектов, которые способны обработать запрос, должен задаваться автоматически.  Шаблон рекомендован для использования в условиях:  в разрабатываемой системе имеется группа объектов, которые могут обрабатывать сообщения определенного типа;  все сообщения должны быть обработаны хотя бы одним объектом системы;  сообщения в системе обрабатываются по схеме «обработай сам либо перешли другому», то есть одни сообщения обрабатываются на том уровне, где они получены, а другие пересылаются объектам иного уровня. 34
  • 35.  Связать объекты - получатели запроса в цепочку и передать запрос вдоль этой цепочки, пока он не будет обработан.  "Обработчик" определяет интерфейс для обработки запросов, и, возможно, реализует связь с преемником,  Преимущества  Ослабляется связанность (объект не обязан "знать", кто именно обработает его запрос).  Недостатки  Нет гарантий, что запрос будет обработан, поскольку он не имеет явного получателя. Шаблонный метод (Template Method)  Проблема  Определить алгоритм и реализовать возможность переопределения некоторых шагов алгоритма для подклассов (без изменения общей структуры алгоритма.  Решение  "АбстрактныйКласс" определяет абстрактные Операции(), замещаемые в конкретных подклассах для реализации шагов алгоритма, и реализует ШаблонныйМетод(), определяющий "скелет" алгоритма. "КонкретныйКласс" релизует Операции(), выполняющие шаги алгоритма способом, который зависит от подкласса. "КонкретныйКласс" предполагает, что инвариантные шаги алгоритма будут выполнены в "АбстрактномКлассе". 35
  • 36. Model-view-controller  Model-view-controller (MVC, «Модель-представление-поведение») — архитектура программного обеспечения, в которой модель данных приложения, пользовательский интерфейс и управляющая логика разделены на три отдельных компонента, так, что модификация одного из компонентов оказывает минимальное воздействие на другие компоненты.  Шаблон MVC позволяет разделить данные, представление и обработку действий пользователя на три отдельных компонента  Модель (Model). Модель предоставляет данные (обычно для View), а также реагирует на запросы (обычно от контролера), изменяя свое состояние .  Представление (View). Отвечает за отображение информации (пользовательский интерфейс).  Поведение (Controller). Интерпретирует данные, введенные пользователем, и информирует модель и представление о необходимости соответствующей реакции. 36
  • 37.  Важно отметить, что как представление, так и поведение зависят от модели. Однако модель не зависит ни от представления, ни от поведения. Это одно из ключевых достоинств подобного разделения. Оно позволяет строить модель независимо от визуального представления.  Впервые данный шаблон проектирования был предложен для языка Smalltalk. Рефакторинг  Рефакторинг или Реорганизация — процесс полного или частичного преобразования внутренней структуры программы при сохранении её внешнего поведения.  В его основе лежит последовательность небольших эквивалентных (т.е., сохраняющих поведение) преобразований.  Поскольку каждое преобразование маленькое, программисту легче проследить за его правильностью, и в то же время, вся последовательность может привести к существенной перестройке программы и улучшению её согласованности и четкости.  Рефакторинг позволяет разрабатывать архитектуру программы постепенно, откладывая проектные решения до тех пор, пока не станет более ясной их необходимость.  Рефакторинг изначально не предназначен для исправления ошибок и добавления новой функциональности, но помогает избежать ошибок и облегчить добавление функциональности.  Наиболее употребимые методы рефакторинга:  Изменение сигнатуры метода (Change Method Signature)  Инкапсуляция поля (Encapsulate Field)  Выделение класса (Extract Class)  Выделение интерфейса (Extract Interface)  Выделение локальной переменной (Extract Local Variable)  Выделение метода (Extract Method)  Генерализация типа (Generalize Type)  Встраивание (Inline) 37
  • 38.      Введение фабрики (Introduce Factory) Введение параметра (Introduce Parameter) Подъём поля/метода (Pull Up) Спуск поля/метода (Push Down) Замена условного оператора полиморфизмом (Replace Conditional with Polymorphism) 38