Проектирование, Архитектура и Конструирование Программных систем
Порождающие паттерны
Интерфейс
Интерфейс
Интерфейс
Интерфейс
Factory method (Создатель)
Factory method
Factory method
Factory method
Factory method
Factory method
Factory method
Factory method
Prototype (Прототип)
Prototype
Prototype
Prototype
Prototype
Prototype
Prototype
Prototype
195.77K
Category: programmingprogramming

ПАКПС 2

1. Проектирование, Архитектура и Конструирование Программных систем

УНИВЕРСИТЕТ ДУБНА
П.СЫЧЕВ
ЛЕКЦИЯ 2

2. Порождающие паттерны

Необходимость в порождающих паттернах в первую очередь связана с задачей
ослабления связей между составляющими сложной программной системы.
Если в реализации класса А необходимо использовать объекты класса В (т.е. либо в полях
класса А есть ссылка на объект класса В, либо объект класса В передается в метод класса А
как параметр), возникает зависимость между классами А и В. Т.е. при изменении класса В
необходимо проверить, что это не повлияло на работу класса А. А если надо заменить
класс В на более совершенный класс В2? Когда речь идет о сложной программной
системе, число классов которой исчисляется тысячами, проследить эти зависимости
исключительно трудно.
Стандартный способ борьбы с сильной связностью – разделить класс на функцию и
конструкцию. Термин функция здесь не из программирования, а из системной инженерии.
Функция – это то, что должен выполнять класс в рамках общей системы.

3. Интерфейс

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

4. Интерфейс

interface IStack <T>
{
void push(T value);
T pop();
bool empty();
T top();
}
Для реализации данного интерфейса необходим класс, реализующий его.

5. Интерфейс

class Stack<T> : IStack<T>
public bool empty()
{
{
List<T> values = new List<T>();
return values.Count == 0;
public void push(T value)
}
{
values.Add(value);
public T top()
}
{
public T pop()
return values[values.Count - 1];
{
}
T val = values[values.Count - 1];
values.RemoveAt(values.Count - 1);
return val;
}
}

6. Интерфейс

Если какому либо классу необходим стек, он будет использовать не класс Stack, а
интерфейс IStack, что существенно ослабляет зависимость.
class My
{
IStack<int> numbers;
// продолжение
}
Но возникает проблема – как инстанцировать эту ссылку? Экземпляр какого класса,
поддерживающего этот интерфейс, должен быть создан и в каком месте.
Для решения таких проблем и используются порождающие паттерны.

7. Factory method (Создатель)

Тип: порождающий.
Синоним: Virtual Constructor.
Назначение: определяет интерфейс для создания объекта, оставляя подклассам решение
о том, какой класс инстанцировать.
Мотивация:
Рассмотрим пример с редактором векторной графики.

8. Factory method

Все фигуры, доступные в данном приложении являются объектами подклассов базового
класса Figure, в нашем примере – Rectangle, Ellipse и Romb.
Здесь пользователь сначала выбирает тип порождаемой фигуры в инструментальном
меню, а потом по клику в рабочей области создается экземпляр соответствующего класса.

9. Factory method

Код метода panel_MouseDown будет
содержать что-то вроде этого, где selection
– поле, содержащее код выбранной
фигуры.
Figure f = null;
switch (selection)
{
Почему это плохо?
case 1:
f = new Rectangle();
Как добавить новую фигуру?
Многие современные программы
работают с плагинами – кодом,
добавляемым во время исполнения
программы. Как добавить новую фигуру
во время исполнения?
break;
case 2:
f = new Ellipse();
break;
}

10. Factory method

Решение
Создать, параллельно с иерархией
классов Figure, иерархию классов
FigureCreator.
class FigureCreator
{
public virtual Figure CreateFigure()
{ return null; }
}
class RectangleCreator : FigureCreator
{
public override Figure CreateFigure()
{
return new Rectangle();
}
}

11. Factory method

Теперь код метода panel_MouseDown будет
более управляемый, где currCreator
соответствующий экземпляр класса
FigureCreator, инициируемый при нажатии на
кнопку выбора создаваемой фигуры.
Figure f = null;
Для добавления новой фигуры надо:
if (currCreator != null)
- написать класс, наследник Figure,
- написать класс, наследник FigureCreator,
- добавить новую кнопку на панель и код
инициализации этого «создателя» на эту
кнопку.
Все!!!
f = currCreator.CreateFigure();

12. Factory method

Структура:

13. Factory method

Участники:
Product – базовый класс для семейства конкретных продуктов, экземпляры которых
должны инстанцироваться;
Creator – базовый класс для семейства «создателей», классы реализующие метод,
создающий новый экземпляр соответствующего класса. Для каждого класса
ConcreteProduct должен быть соответствующий класс ConcreteCreator, задача которого
изготавливать экземпляры класса ConcreteProduct.
Реализация: в большинстве случаев не вызывает проблем.

14. Factory method

Результаты:
(+) снижает зависимость между классами. В нашем примере редактор работает только с
экземплярами класса Figure, экземпляры конкретных классов создаются с помощью
«создателя».

15. Prototype (Прототип)

Тип: порождающий.
Синоним: нет.
Назначение: создание нового объекта путем клонирования существующего прототипа.
Мотивация:
В качестве примера рассмотрим нотный редактор. В качестве рабочей области в нем будет
нотный стан, а в качестве инструментальной линейки – набор нот разной высоты и
длительности.
Основным объектом в такой программе будет нота – класс Note.

16. Prototype

Вопрос: как создавать новые
экземпляры этого класса? Что
делать по клику в
инструментальной панели?
Решение: добавить в класс
Note метод Clone(), создающий
точную копию объекта. С
каждой кнопкой связать
экземпляр класса Note, копию
которого и вставлять в
программу.

17. Prototype

Второй пример – группировка различных фигур в векторном редакторе. Если вы
сгруппировали интересную для вас композицию (точка, точка, два кружочка …), то как ее
поместить на инструментальную панель. Точнее – что делать при нажатии на эту кнопку и
как создать новый экземпляр этой группы?
Решение: как и в предыдущем случае добавим в базовом классе Figure метод Clone,
создающий копию объекта. Соответствующий кнопке «создатель» будет иметь копию
группы как прототип создаваемого объекта, и в методе CreateFigure – создавать и
возвращать копию своего прототипа.

18. Prototype

Структура:

19. Prototype

Участники:
Client – класс, использующий этот паттерн. В нашем случае, например, векторный
редактор. Он содержит ссылку на прототип, который может быть инстанцирован объектом
любого класса – наследника Prototype.
Prototype – базовый абстрактный класс для семейства классов, поддерживающих
операцию Clone(), метод позволяющий получить копию объекта.
ConcretePrototype1, ConcretePrototype2 – классы наследующие Prototype и реализующие
метод Clone.

20. Prototype

Реализация:
1.
Основная проблема в реализации метода Clone – определить глубокое (deep) или
мелкое (shallow) копирование объекта.
Общий подход к реализации метода простой. Надо создать новый экземпляр и
скопировать туда значение полей объекта. Разница возникает, когда поле объекта
содержит ссылку на другой объект какого-то класса. Если дубликат получает копию ссылки,
то это мелкое копирование. Если ссылаемый объект, в свою очередь, дублируется и
дубликат получает ссылку на копию объекта, то это глубокое копирование.
Никакого правильного ответа на этот вопрос нет. В различных случаях надо использовать
разное решение.

21. Prototype

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

22. Prototype

Результаты:
(+) ослабление связности
(+) возможно добавление и удаление прототипов во время выполнения
(+) спецификация новых прототипов путем изменения значений
(+) динамическое конфигурирование приложения набором прототипов
English     Русский Rules