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/
Бреслав А. А.
Паттерны проектирования. Введение
Вопросы
Бреслав А. А.
Паттерны проектирования. Введение