Software Design Паттерны проектирования Бреслав А. А. Что такое «хороший дизайн» Точного универсального ответа на этот вопрос нет  Есть стандартные решения для определенных задач –

Download Report

Transcript Software Design Паттерны проектирования Бреслав А. А. Что такое «хороший дизайн» Точного универсального ответа на этот вопрос нет  Есть стандартные решения для определенных задач –

Software Design
Паттерны проектирования
Бреслав А. А.
Что такое «хороший дизайн»
Точного универсального ответа на этот
вопрос нет
 Есть стандартные решения для
определенных задач – паттерны

 Предложены
хорошими специалистами
 Проверены временем
 Составляют удобный словарь для общения
Бреслав А. А.
Паттерны проектирования. Введение
Gang of Four (GoF)

Книга Э. Гаммы, Р. Хелма, Р. Джонсона и
Дж. Влиссидеса – «банда четырех»
 Вышла
в 1995 году
 Примеры на C++, кое-что на SmallTalk

С тех пор ничего принципиально нового
не придумали
 Примеры
для других языков
 Несколько новых паттернов
Бреслав А. А.
Паттерны проектирования. Введение
Что такое паттерн проектирования

Типовая схема решения определенной
задачи
 Название
(возможно, несколько)
 Описание задачи
 Схема решения
 Обсуждение результатов
Бреслав А. А.
Паттерны проектирования. Введение
Пример: Observer / Listener

Названия:
 «Observer»


(GoF) / «Listener» (JDK)
Задача: один объект должен оповещать
несколько других о том, что произошло
некоторое событие (например, его состояние
изменилось)
Решение:
 создать
интерфейс Listener
 регистрировать слушателей в объекте-сервере
Бреслав А. А.
Паттерны проектирования. Введение
Listener: реализация в Java

interface Listener {
 void
eventMethod(EventObject e);

}

class Server {
 private final Collection<Listener> listeners;
 public void addListener(Listener l) {…}
 public void removeListener(Listener l)
 public void fireEvent(EventObject e) {
 for (Listener listener : listeners) {


listener.eventMethod(e);
}
}
Бреслав А. А.
Паттерны проектирования. Введение
{…}
Другой пример: Iterator
Какова задача?
 Каково решение?
 Какие особенности есть у Javaреализации

Бреслав А. А.
Паттерны проектирования. Введение
Что не является паттерном

Готовый класс
 Структуры
данных
 Потоки
и

т. д.
Архитектура в целом
 Client-Server
 MVC
Бреслав А. А.
Паттерны проектирования. Введение
Для чего применяются паттерны

Чтобы создать хороший дизайн 
 Инкапсуляция
 Повторное
использование
 Снижение зависимостей
…
Бреслав А. А.
Паттерны проектирования. Введение
Классификация паттернов (GoF)

Порождающие паттерны
 Организуют

Структурные паттерны
 Организуют

структуру классов
Паттерны поведения
 Организуют

создание объектов
поведение объектов
Пример: Observer – паттерн поведения
Бреслав А. А.
Паттерны проектирования. Введение
Несколько основных паттернов

Singleton – порождение


Template Method – поведение


Factory Method – порождение
Wrapper – структура





Type-safe enumeration
Adapter
Decorator
Composite
Proxy
Strategy – поведение




Command
State
Builder – порождение
Abstract Factory – порождение
Бреслав А. А.
Паттерны проектирования. Введение
Singleton – «одиночка»

Может существовать всего один объект данного
класса



Например, когда важно только поведение, а не состояние
(Comparator)
Отличие от класса со статической реализацией:
полиморфизм, можно поддержать некоторый
интерфейс
Примеры:


String.CASE_INSENSITIVE_ORDER
Обобщение – type-safe enumeration


Бреслав А. А.
Boolean (TRUE и FALSE)
enum в Java 5
Паттерны проектирования. Введение
Singleton: реализация в Java
private-конструктор
 Единственный объект - константа
 Ленивая инициализация:

 не
нужно создавать объект, если он никому
не понадобился
Бреслав А. А.
Паттерны проектирования. Введение
Singleton: пример кода (1)
public class Singleton implements Comparator {
private static Singleton INSTANCE;
private Singleton() {
}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
public int compare(Object o1, Object o2) {
return …;
}
}
Бреслав А. А.
Паттерны проектирования. Введение
Singleton: пример кода (2)
public class Singleton {
public static final Singleton INSTANCE =
new Singleton();
private Singleton() {
}
public int compare(Object o1, Object o2) {
return …;
}
}
Бреслав А. А.
Паттерны проектирования. Введение
Singleton: пример кода (3)
public enum Singleton implements Comparator {
INSTANCE;
public int compare(Object o1, Object o2) {
return …;
}
}
Ограничение: нельзя наследоваться от другого
класса
Бреслав А. А.
Паттерны проектирования. Введение
Template method – шаблонный
метод
Метод регламентирует порядок вызова
других методов, реализуемых в
подклассах
 Примеры:

 AbstractCollection
 Nonvirtual
Бреслав А. А.
Interface
Паттерны проектирования. Введение
Template method – реализация в
Java
Сам метод, как правило, объявляется
final
 Методы, которые он вызывает, обычно

 объявляются
protected
 абстрактные, но могут иметь и
«реализацию по умолчанию»
Бреслав А. А.
Паттерны проектирования. Введение
Template method – пример кода
public abstract class TemplateMethodExample {
public final void perform() {
try {
doPerform();
} catch (IllegalStateException e) {
handleException(e);
}
}
protected abstract void doPerform()
throws IllegalStateException;
protected abstract void
handleException(IllegalStateException e);
}
Бреслав А. А.
Паттерны проектирования. Введение
Factory method – фабричный
метод
Частный случай Template method
 Полиморфный метод для создания
объектов
 В подклассах его можно
переопределить, чтобы создавать
объекты специфичных классов

Бреслав А. А.
Паттерны проектирования. Введение
Factory method

Возможность кеширования
 Integer.valueOf(int)

Возможность подмены реализации
В
будущем можно возвращать объекты
класса-наследника, не изменяя клиентов

Бреслав А. А.
при явном вызове конструктора так не
получится
Паттерны проектирования. Введение
Factory method – пример кода
public abstract class MultiMap {
private final Map map = new HashMap();
public Object get(Object[] keys) {
return map.get(createKey(keys));
}
public void put(Object[] keys, Object value) {
map.put(createKey(keys), value);
}
public abstract Object createKey(Object[] keys);
}
Бреслав А. А.
Паттерны проектирования. Введение
Идея: делегирование


Некоторый объект сам не выполняет
некоторое действие, а вызывает
соответствующие методы другого объекта
Пример: правильная реализация стека
 class Stack<E> {
 private final List<E> data = …;
 public void push(E element) {...}
 public E pop() throws StackUnderflowException {…}
 public boolean isEmpty() {…}
}
 Стек делегирует хранение данных списку
Бреслав А. А.
Паттерны проектирования. Введение
Wrapper - Обертка


«Обертка» - один объект «завернут» в другой,
при чем «обертка» делегирует завернутому
часть функций
Возможности
 Замена наследования делегированием
 Иногда заменяет множественное наследование классов
 Создание
 subList

представлений
Пример: List завернут в Stack
Бреслав А. А.
Паттерны проектирования. Введение
Adapter - Адаптер




Частный случай Wrapper
Задача: для некоторой цели нужно использовать
класс, API которого для этой цели не подходит
Решение: создать класс с нужным интерфейсом,
делегирующий существенные операции исходному
классу
Примеры:



StringReader
InputStreamReader
JUnit4TestAdapter
Бреслав А. А.
Паттерны проектирования. Введение
Adapter – реализация в Java
Класс-адаптер имеет конструктор,
принимающий объект адаптируемого
класса
 Как правило, есть метод,
возвращающий «завернутый» объект

Бреслав А. А.
Паттерны проектирования. Введение
Adapter – пример кода
public class IntAsBitList extends
AbstractList<Integer> {
private int value;
public IntAsBitList(int x) {
value = x;
}
public Integer get(int index) {
if ((index < 0) || (index > size())) {
throw new IndexOutOfBoundsException();
}
return (value & (1 << index)) >> index;
}
public int size() {
return 32;
}
}
Бреслав А. А.
Паттерны проектирования. Введение
Decorator - Декоратор




Частный случай Wrapper
Задача: нужен объект с тем же интерфейсом,
что и имеющийся, но добавляющий к
операциям дополнительные действия
Решение: создадим обертку, которая будет
выполнять дополнительные действия, а
остальное делегировать
Примеры
 сheckedCollection
 FilterInputStream
Бреслав А. А.
Паттерны проектирования. Введение
Decorator – реализация в Java

Для описания API используется
интерфейс
 один
объект практически полностью
делегирует все действия другому

Возможна реализация с помощью
наследования и переопределения
методов
 такая
реализация не позволяет добавить
декоратор во время выполнения
Бреслав А. А.
Паттерны проектирования. Введение
Decorator – пример кода (1)
public interface TreeWalker {
void visit(Node node);
}
public class NoLeavesWalker implements TreeWalker {
private final TreeWalker impl;
public NoLeavesWalker(TreeWalker impl) {
this.impl = impl;
}
public void visit(Node node) {
if (node.getLeft() != null
|| node.getRight() != null) {
impl.visit(node);
}
}
}
Бреслав А. А.
Паттерны проектирования. Введение
Decorator – пример кода (2)
public class TreeSummer
implements TreeWalker {
private int sum = 0;
public void visit(Node node) {
sum += node.getData();
}
}
// Для суммирования значений только
// во внутренних вершинах
new NoLeavesWalker(new TreeSummer());
Бреслав А. А.
Паттерны проектирования. Введение
Composite - Компоновщик
Составной объект имеет тот же
интерфейс, что и одиночный
 В некотором смысле, частный случай
Wrapper
 Пример

 Container,

Бреслав А. А.
JComponent
Окно, содержащее дочерние окна, имеет тот же
API, что и одиночное окно
Паттерны проектирования. Введение
Composite – реализация в Java
Общий интерфейс для композитных и
одиночных объектов
 Композитный класс

 реализует
этот интерфейс
 имеет набор дочерних объектов
 методы вызывают такие же методы от
дочерних объектов
Бреслав А. А.
Паттерны проектирования. Введение
Composite – пример кода (1)
public interface Processor {
void process(Object data);
}
public class CompositeProcessor implements Processor {
private final Processor[] children;
public CompositeProcessor(Processor... processors) {
children = processors.clone();
}
public void process(Object data) {
for (Processor child : children) {
child.process(data);
}
}
}
Бреслав А. А.
Паттерны проектирования. Введение
Composite – пример кода (2)
public class ValuePrinter
implements Processor {
public void process(Object data) {
System.out.println("value: " + data);
}
}
public class AddressPrinter
implements Processor {
public void process(Object data) {
System.out.println("address: " +
System.identityHashCode(data));
}
}
Бреслав А. А.
Паттерны проектирования. Введение
Composite – пример кода (3)
Processor valuePrn = new ValuePrinter();
valuePrn.process(10);
Processor addressPrn = new AddressPrinter();
Processor composite = new
CompositeProcessor(valuePrn, addressPrn);
composite.process(10);
/* Вывод:
value: 10
value: 10
address: 26399554
*/
Бреслав А. А.
Паттерны проектирования. Введение
Proxy – Заместитель

Задача
 Полная
инициализация некоторого объекта –
очень трудоемкая операция
 Очень возможно, что полная инициализация не
понадобится
 То, что точно понадобится, можно получить
достаточно легко
 Нужно организовать ленивую инициализацию
Бреслав А. А.
Паттерны проектирования. Введение
Решение: Proxy

Вместо самого объекта использовать его
заместителя
 Поддерживает
тот же интерфейс
 Инициализирует только то, что легко
инициализировать
 Если понадобится, полностью инициализирует
объект и делегирует ему все действия

Специфичный случай Decorator
Бреслав А. А.
Паттерны проектирования. Введение
Proxy: пример

Картинки в документе HTML (или Word)
 Загрузка
– трудоемкое дело
 Для форматирования документа необходимо знать
только размеры
 Документ могут не прокрутить до очередной
картинки

Используем Proxy для картинок
 Информацию
о размерах получим быстро
 Изображения будем загружать в фоновом режиме
Бреслав А. А.
Паттерны проектирования. Введение
Strategy - Стратегия



Задача: передать участок кода в качестве
значения (например, параметра методу)
Решение: определить API этого кода,
реализовать его и передать объект
реализации
Примеры:
 Comparator
 Observer
(Listener)
 LayoutManager
Бреслав А. А.
Паттерны проектирования. Введение
Strategy – реализация в Java
Как правило, API регламентируется
интерфейсом
 Часто для реализации применяются
анонимные inner-классы
 Стратегии часто бывают синглтонами

Бреслав А. А.
Паттерны проектирования. Введение
Strategy – пример кода (1)
public class StrategyExample {
interface Filter { // Стратегия
boolean accept(char c);
}
public static String
filterString(String s, Filter f) {
StringBuilder b = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (f.accept(s.charAt(i))) {
b.append(s.charAt(i));
}
}
return b.toString();
}
}
Бреслав А. А.
Паттерны проектирования. Введение
Strategy – пример кода (2)
public static void main(String[] args) {
Filter strategy = new Filter() {
public boolean accept(char c) {
return Character.isDigit(c);
}
};
System.out.println(
filterString("123hgf231", strategy));
}
Бреслав А. А.
Паттерны проектирования. Введение
Strategy – пример кода (3)
public static void main(String[] args) {
System.out.println(
filterString("123hgf231", new Filter() {
public boolean accept(char c) {
return Character.isDigit(c);
}
}));
}
Бреслав А. А.
Паттерны проектирования. Введение
Command - Команда

Задача:
 постановка
операций в очередь
 реализация undo
Решение: представить операцию в виде
объекта
 Частный случай Strategy

Бреслав А. А.
Паттерны проектирования. Введение
Command – реализация в Java

Интерфейс Command содержит метод для
запуска команды и, возможно, метод для
отмены команды
 часто

эти методы не имеют параметров
Каждый объект команды хранит все
параметры команды
 поэтому

возможно undo
Дополнительная функция: проверка
возможности применения/отмены команды
Бреслав А. А.
Паттерны проектирования. Введение
Command – пример кода (1)
public interface Command {
void execute();
void undo();
}
private Queue<Command> commandQueue =
new LinkedList<Command>();
private Stack<Command> undoStack = new Stack<Command>();
public void runNextCommand() {
Command command = commandQueue.remove();
undoStack.push(command);
command.execute();
}
public void undo() {
undoStack.pop().undo();
}
Бреслав А. А.
Паттерны проектирования. Введение
Command – пример кода (2)
public class IncCommand implements Command {
private final int index;
private final int delta;
public IncCommand(int index, int delta) {
this.index = index;
this.delta = delta;
}
public void execute() {
array[index] += delta;
}
public void undo() {
array[index] -= delta;
}
}
Бреслав А. А.
Паттерны проектирования. Введение
State – Состояние



Задача: кардинальное изменение поведения
объекта при изменении состояния
Решение: создать класс состояния и
делегировать объекту этого класса
варьируемое поведение. При изменении
состояния подменяется объект состояния.
Частный случай Strategy
 Состояние
Бреслав А. А.
– стратегия поведения
Паттерны проектирования. Введение
Пример: графический редактор

При выборе инструмента поведение
редактора сильно изменяется
 Реакции
на действия мыши
 Реакции на нажатия клавиш клавиатуры

Инструмент – объект состояния
 Ему
делегируется изменяющееся
повеедение
Бреслав А. А.
Паттерны проектирования. Введение
State – реализация в Java





API состояния задается интерфейсом
Каждое состояние обычно singleton
Состояния часто образуют enum
Текущее состояние хранится в некотором
поле
Если состояние обрабатывает события, не
стоит добавлять его как Listener
 лучше
добавить listener один раз, а он будет
делегировать все текущему состоянию
Бреслав А. А.
Паттерны проектирования. Введение
State – пример кода (1)
interface Tool extends MouseListener { }
…
private Tool currentTool;
private final MouseListener
mouseListener = new MouseListener() {
public void mouseClicked(MouseEvent e) {
currentTool.mouseClicked(e);
}
public void mouseEntered(MouseEvent e) {
currentTool.mouseEntered(e);
}
…
}
Бреслав А. А.
Паттерны проектирования. Введение
State – пример кода (2)
private final Tool defaultTool = new Tool() {
public void mouseClicked(MouseEvent e) {
// …
}
public void mouseEntered(MouseEvent e) {
// …
}
…
}
public void selectTool(Tool tool) {
currentTool = tool;
}
Бреслав А. А.
Паттерны проектирования. Введение
Builder – Строитель
Задача: из одного и того же набора
данных могут конструироваться разные
объекты
 Решение: определить API строителя –
класса, от реализации которого будет
зависеть, что будет создано
 Частный случай Strategy

Бреслав А. А.
Паттерны проектирования. Введение
Builder – пример

Разбор HTML
 Типы создаваемых объектов
 PlainTextBuilder создает обычный текст
 HTMLDOMBuilder создает иерархию HTML-объектов
 GIFBuilder создает картинку
 HTMLBuilder копирует HTML
 Интерфейс строителя
 Тег открыт
 Встретился текст
 Тег закрыт
Бреслав А. А.
Паттерны проектирования. Введение
Builder – схема работы
tagOpened()
Target
object(s)
Builder
textFound()
HTML
Parser
tagClosed()
Бреслав А. А.
Паттерны проектирования. Введение
<html>
<head>
<title>
Builders
</title>
</head>
<body>
Hello!
</body>
</html>
Abstract Factory
Задача: есть набор интерфейсов
(абстрактных классов), создать для
каждого из них объекты-реализации так,
чтобы они были согласованы
 Решение: абстрактная фабрика –
стратегия создания объектов

Бреслав А. А.
Паттерны проектирования. Введение
Abstract Factory - пример
GraphFactory
Graph
Vertex
Edge
WayVertex
WeightedEdge
+createGraph()
+createVertex()
+createEdge()
ListGraphFactory
ListGraph
MatrixGraph
way
WeightedGraphFactory
Бреслав А. А.
Паттерны проектирования. Введение
weight
Abstract Factory - использование
Обходы графа – SimpleGraphFactory
 Алгоритмы поиска кратчайших путей –
WeightedGraphFactory
 Для создания собственного набора
данных в вершине/ребре – новая
реализация фабрики

Бреслав А. А.
Паттерны проектирования. Введение
Источники



Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес,
«Приемы объектно-ориентированного
проектирования. Паттерны проектирования»
М. Гранд, «Шаблоны проектирования в Java»
Bruce Eckel, «Thinking in Patterns with Java»
 http://www.mindviewinc.com/
Бреслав А. А.
Паттерны проектирования. Введение
Вопросы
Бреслав А. А.
Паттерны проектирования. Введение