Скачать презентацию
Идет загрузка презентации. Пожалуйста, подождите
Презентация была опубликована 10 лет назад пользователемФилипп Михалков
1 Шаблоны проектирования Design Pattern Декоратор, оформитель (Decorator) по книге Эрик и Элизабет Фримен Паттерны проектирования
2 2 Система заказов и реальный ассортимент Сеть кофеен Starbuss Beverage getDescription() cost() // другие методы … description HouseBlend cost() DarckRoast cost() Decaf cost() Espresso cost() Классы заказов для вычисления стоимости
3 3 Дополнения к кофе К кофе можно заказать различные дополнения (пенка, шоколад и т. д.), да еще украсить все сверху взбитыми сливками. Дополнения не бесплатны, поэтому они должны быть встроены в систему оформления заказов. Первая попытка.. Классы размножаются!!!
4 4 Версия cost() суперкласса вычисляет стоимость всех компонентов, а переопределенная версия добавляет стоимость конкретного напитка Beverage getDescription() cost() hasMilk() setMilk() hasSoy() setSoy() … description milk soy mocha whip HouseBlend cost() Decaf cost() Espresso cost() DarckRoast cost() Глупо! Зачем нужны все эти классы? Разве для отслеживания дополнений нельзя использовать переменные экземпляров в суперклассе и наследование?
5 5 Возможные изменения требований Изменение цены дополнений потребует модификации существующего кода. При появлении новых дополнений нам придется добавлять новые методы и изменять реализацию cost() в суперклассе. Для некоторых новых напитков (холодный чай?) дополнения могут оказаться неуместными, но субкласс Tea все равно будет наследовать hasWhip() и другие методы. А если клиент захочет двойную порцию шоколада? Потенциальные недостатки такого подхода видны, если подумать о возможных изменениях в будущем
6 6 Наследование и композиция Наследование обладает большими возможностями, но оно не всегда приводит к самой гибкой или удобной в сопровождении архитектуре. Поведение, унаследованное посредством субклассирования, задается статически на стадии компиляции. Кроме того, оно должно наследоваться всеми субклассами. Расширение поведения объекта посредством композиции может осуществляться динамически. Сила композиции в том, что можно наделить объект новыми возможностями даже теми, которые не были предусмотрены при проектировании суперкласса. При этом не придется изменять его код. Динамическая композиция объектов позволяет добавлять новую функциональность посредством написания нового кода (вместо изменения существующего).
7 7 Принцип открытости/закрытости Один из важнейших принципов проектирования Принцип проектирования Классы должны быть открыты для расширения, но закрыты для изменения Цель заключается в том, чтобы классы можно было легко расширять новым поведением без изменения существующего кода. Что это дает? Архитектуры, устойчивые к изменениям и достаточно гибкие для поддержки новой функциональности в соответствии с изменившимися требованиями. Будьте осторожны с выбором расширяемых областей. ПОВСЕМЕСТНОЕ применение принципа открытости/закрытости неэффективно и расточительно, оно приводит к созданию сложного, малопонятного кода.
8 8 Знакомство с паттерном декоратор Схема вычисления стоимости напитка с дополнениями посредством декорирования. Например, если клиент заказывает кофе темной обжарки (Dark Roast) с шоколадом (Mocha) и взбитыми сливками (Whip), то: берем объект DarkRoast; декорируем его объектом Mocha; декорируем его объектом Whip; вызываем метод cost() и пользуемся делегированием для прибавления стоимости дополнений. Но как «декорировать» объект, и как в этой схеме работает делегирование?
9 9 cost() Декоратор Whip тоже повторяет Beverage и содержит свой метод cost(). Построение заказанного напитка cost() Объект Mocha – декоратор. Поэтому его тип тоже Beverage. И он содержит свой метод cost() cost() DarkRoast наследует от Beverage Таким образом, объект DarkRoast «завернутый» в Mocha и Whip сохраняет признаки Beverage, и с ним можно делать все, что можно делать с DarkRoast, включая вызов метода cost().
10 10 Вычисление общей стоимости напитка cost() $1.29
11 11 Определение паттерна Декоратор Что уже известно Декораторы имеют тот же супертип, что и декорируемые объекты. Объекты можно «завернуть» в один или несколько декораторов. Так как декоратор относится к тому же типу, что и декорируемый объект, можно передать декорированный объект вместо исходного. Декоратор добавляет свое поведение до и(или) после делегирования операций декорируемому объекту, выполняющему остальную работу. Объект может быть декорирован в любо момент времени, так что можно декорировать объекты динамически произвольным количеством декораторов. Паттерн Декоратор динамически наделяет объект новыми возможностями и является гибкой альтернативой субклассированию в области расширения функциональности.
12 12 Диаграма классов Компонент может использоваться как сам по себе, так и «завернутым» в декоратор Декоратор содержит компонент Component metodA() metodB() // другие методы ConcreteComponent metodA() metodB() // другие методы ConcreteDecoratorA metodA() metodB() newBehavior() // другие методы Decorator metodA() metodB() // другие методы Component wrappedObj Object newState metodA() metodB() // другие методы ConcreteDecoratorB Декоратор реализует тот же интерфейс (расширяет класс), что и декорируемый компонент Объект, поведение которого надо расширить динамически, является субклассом Component Декораторы могут расширять состояние компонента Декораторы могут добавлять новые методы ( до или после вызова существующего метода)
13 13 Иерархия напитков Beverage getDescription() cost() // другие методы … description HouseBlend cost() DarckRoast cost() Decaf cost() Espresso cost() CondimentDecorator getDescription() Beverage beverage Milk cost() getDescription() Mocha cost() getDescription() Soy cost() getDescription() Whip cost() getDescription() Наследование ДЛЯ согласовани типов, а НЕ ДЛЯ обеспечения поведения Поведение добавляется посредством композиции Вместо абстрактного класса (Beverage) можно пользоваться интерфейсом реализация Starbuzz
14 14 Ввод/вывод в языке Java Типичный набор объектов, использующих декораторы для расширения функциональности чтения данных из файла: BufferedInputStream и LineNumberlnputStream расширяют FilterInputStream - абстрактный класс декоратора. Конкретный декоратор LineNumberlnputStream добавляет возможность подсчета строк в процессе чтения данных. Конкретный декоратор BufferedlnputStream буферизует ввод для повышения производительности и дополняет интерфейс новым методом readLine() для построчного чтения символьных данных Текстовый файл FilelnputStream декорируемый компонент, библиотека ввода/вывода Java предоставляет базовые компоненты FilelnputStream, StringBufferlnputStream, ByteArrayInputStream, предназначенные для чтения байтов данных.
15 15 Декорирование классов java.io Абстрактный компонент Абстрактный декоратор Конкретные декораторы Конкретные компоненты InputStream FileInputStream PushbackInputStreamDataInputStream BufferedInputStream StringBuferedInputStream ByteArrayInputStream FilterInputStream LineNumberInputStream Выходные потоки используют аналогичную архитектуру. Потоки Reader/Writer (для символьных данных) достаточно близко отражают архитектуру потоковых классов. собственная реализация декоратора ввода/вывода
16 16 Ограничения на использование Декоратор – отличный паттерн для создания гибких архитектур и соблюдения принципа открытости/закрытости. Одно из главных достоинств заключается в том, что декораторы обычно вводятся в архитектуру прозрачно, а клиенту даже не нужно знать, что он имеет дело с декоратором. Ограничения Добавляет в архитектуру много мелких классов, и разобраться в ней становится весьма непросто. Если код зависит от конкретных типов, а вы применяете обобщенные декораторы, дело добром не кончится. Введение декораторов усложняет код создания экземпляра компонента. Если в архитектуре участвуют декораторы, необходимо не только создать компонент, но и «завернуть» его в сколько-то декораторов.
17 17 Резюме Концепции ООП Абстракция Инкапсуляция Полиморфизм Наследование Стратегия определяет семейство алгоритмов, инкапсулирует каждый из них и обеспечивает их взаимозаменяемость. Он позволяет модифицировать алгоритмы независимо от их использования на стороне клиента. Наблюдатель определяет отношение «один- ко-многим» таким образом, что при изменений состояния одного объекта происходит автоматическое оповещение и обновление всех зависимых объектов. Принципы Инкапсулируйте, то что изменяется Отдавайте предпочтение композиции перед наследованием Программируйте на уровне интерфейсов, а не реализации Стремитесь к слабой связаности взаимодействующих объектов Классы должны быть открыты для расширения, но закрыты для изменения Паттерн Декоратор динамически наделяет объект новыми возможностями и является гибкой альтернативой субклассированию в области расширения функциональности.
18 18 Ключевые моменты Наследование одна из форм расширения, но оно не всегда обеспечивает гибкость архитектуры. Следует предусмотреть возможность расширения поведения без изменения существующего кода. Композиция и делегирование часто используются для динамического добавления нового поведения. Паттерн Декоратор предоставляет альтернативу субклассированию в области расширения поведения. Типы декораторов соответствуют типам декорируемых компонентов (соответствие достигается посредством наследования или реализации интерфейса). Декораторы изменяют поведение компонентов, добавляя новую функциональность до и (или) после (или даже вместо) вызовов методов компонентов. Компонент может декорироваться любым количеством декораторов. Декораторы обычно прозрачны для клиентов компонента (если клиентский код не зависит от конкретного типа компонента).
Еще похожие презентации в нашем архиве:
© 2024 MyShared Inc.
All rights reserved.