'

Шаблоны проектирования Design Pattern

Понравилась презентация – покажи это...





Слайд 0

Шаблоны проектирования Design Pattern Фабрика (Factory) по книге Эрик и Элизабет Фримен Паттерны проектирования


Слайд 1

2 Создание объектов Мы не должны программировать на уровне реализации, но ведь при каждом вызове new мы именно это и делаем, верно? Duck duck = new MallardDack(); В программе создаются экземпляры разных конкретных классов, причем класс выбирается во время выполнения в зависимости от неких условий. Часто подобный код размещается в разных частях приложения, что основательно затрудняет его сопровождение и обновление. Видим new подразумеваем конкретный


Слайд 2

3 Чем плох оператор new? Но ведь объект нужно как-то создать, а в Java существует только один способ, верно? Так о чем тут говорить? С ним все в порядке. Проблемы создает ИЗМЕНЕНИЕ и его влияние на использование new Вспомним первый принцип проектирования: определить аспекты, которые будут меняться, и отделить их от тех, которые останутся неизменными


Слайд 3

4 Определение изменяемых аспектов Допустим, вы открыли пиццерию Pizza orderPizza(){ Pizza pizza = new Pizza(); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } Но есть много разновидностей пиццы Pizza orderPizza(String type){ Pizza pizza; if(type.equals(“cheese”)){ pizza = new CheesePizza(); }else if(type.equals(“greek”)){ pizza = new GreekPizza(); }else if(type.equals(“pepperoni”)){ pizza = new PepperoniPizza(); } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; }


Слайд 4

5 Добавление новых типов пиццы Со временем этот код придется менять снова и снова В целом процедура приготовления, выпечки и упаковки остается неизменной


Слайд 5

6 Инкапсуляция создания объектов Переместим код создания объектов в другой объект, единственной задачей которого будет создание объектов пиццы Pizza orderPizza(String type){ Pizza pizza; pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } Код выделяется в объект, который занимается только созданием пиццы и ничем более. Код создания объекта if(type.equals(“cheese”)){ pizza = new CheesePizza(); }else if(type.equals(“greek”)){ pizza = new GreekPizza(); }else if(type.equals(“pepperoni”)){ pizza = new PepperoniPizza(); }else if(type.equals(“clam”)){ pizza = new ClamPizza(); }else if(type.equals(“veggie”)){ pizza = new VeggiePizza(); }


Слайд 6

7 назовем его Фабрикой Фабрика инкапсулирует подробности создания объектов. Метод orderPizza() становится обычным клиентом фабрики SimplePizzaFactory. Каждый раз, когда ему понадобится новая пицца, он просит фабрику ее создать. Прошли те времена, когда метод orderPizza() должен был знать, чем греческая пицца отличается от вегетарианской. Теперь метод orderPizza() знает лишь то, что полученный им объект реализует интерфейс Pizza для вызова методов prepare(), bake(), cut() и box().


Слайд 7

8 Класс SimplePizzaFactory public class SimplePizzaFactory{ public Pizza createPizza(String type){ Pizza pizza = null; if(type.equals(“cheese”)){ pizza = new CheesePizza(); }else if(type.equals(“pepperoni”)){ pizza = new PepperoniPizza(); }else if(type.equals(“clam”)){ pizza = new ClamPizza(); }else if(type.equals(“veggie”)){ pizza = new VeggiePizza(); } return pizza; } } Занимается исключительно созданием пиццы для своих клиентов Код параметризуется по типу пиццы


Слайд 8

9 Переработка класса PizzaStore public class PizzaStore{ SimplePizzaFactory factory; public PizzaStore(SimplePizzaFactory factory){ this.factory = factory; } Pizza orderPizza(String type){ Pizza pizza = factory.createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } } Вызов оператора new заменяется вызовом метода create объекта фабрики. Никаких создания экземпляров конкретного типа


Слайд 9

10 Простая фабрика Фабрика должна быть единственной частью приложения, работающей с конкретными классами пиццы этот метод часто бывает статическим Клиент обращается к фабрике для получения объектов Продукт, производимый фабрикой (абстрактный класс или интерфейс) Конкретные продукты, реализующие интерфейс Pizza* (то что отдают клиенту) Реализация (SimpleFactory)


Слайд 10

11 Расширение бизнеса Вы планируете открыть целую сеть пиццерий PizzaStore по всей стране. Чтобы обеспечить высокое качество пиццы вы требуете, чтобы они использовали ваш проверенный код. Но что делать с региональными различиями? SimplePizzaFactory заменяется разными фабриками: NYPizzaFactory, ChicagoPizzaFactory, CaliforniaPizzaFactory. В этом случае PizzaStore связывается с подходящей фабрикой посредством композиции.


Слайд 11

12 Реализация расширения NYPizzaFactory nyFactory = new NYPizzaFactory(); PizzaStore nyStore = new PizzaStore(nyFactory); Pizza veggie = nyStore.order("Veggie") ; Сначала создаем фабрику для пиццы в нью-йоркском стиле. Затем создаем объект PizzaStore и передаем ему ссылку на фабрику. При создании экземпляров получаем пиццу в нью-йоркском стиле ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory(); PizzaStore chicagoStore = new PizzaStore(chicagoFactory); Pizza veggie = chicagoStore.order("Veggie");


Слайд 12

13 Проблема с качеством Пиццерии вашей сети используют ваши фабрики для создания пиццы, но в остальных фазах процесса применяют свои доморощенные правила: выбирают свой режим выпечки, забывают нарезать пиццу, используют упаковку сторонних фирм и т. д. Нам нужна инфраструктура, которая связывает пиццерию с процессом создания пиццы, но при этом сохраняет достаточную гибкость. Кто знает, ЧТО он кладет в свою пиццу ?!!!


Слайд 13

14 Инфраструктура для пиццерии Мы хотим локализовать все операции по изготовлению пиццы в классе PizzaStore, но при этом сохранить для пиццерий достаточную гибкость для выбора своего регионального стиля. Для этого мы вернем метод createPizza() в класс PizzaStore, но в виде абстрактного метода, а затем создадим субкласс для каждого регионального стиля. public abstract class PizzaStore{ Pizza orderPizza(String type){ Pizza pizza = createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } abstract Pizza createPizza(String type); } «Фабричный метод» стал абстрактным методом PizzaStore


Слайд 14

15 public Pizza createPizza(String type){ Pizza pizza = null; if(type.equals(“cheese”)){ pizza = new ChicagoStyleCheesePizza(); }else if(type.equals(“pepperoni”)){ pizza = new ChicagoStylePepperoniPizza(); }else if(type.equals(“clam”)){ pizza = new ChicagoStyleClamPizza(); }else if(type.equals(“veggie”)){ pizza = new ChicagoStyleVeggiePizza(); } return pizza; } public Pizza createPizza(String type){ Pizza pizza = null; if(type.equals(“cheese”)){ pizza = new NYStyleCheesePizza(); }else if(type.equals(“pepperoni”)){ pizza = new NYStylePepperoniPizza(); }else if(type.equals(“clam”)){ pizza = new NYStyleClamPizza(); }else if(type.equals(“veggie”)){ pizza = new NYStyleVeggiePizza(); } return pizza; } Принятие решения в субклассах Субклассы определяют тип пиццы, которая будет создана по запросу Метод orderPizza() суперкласса понятия не имеет, какой из типов пиццы мы создаем; он знает лишь то, что пиццу можно приготовить, выпечь, нарезать и упаковать!


Слайд 15

16 Объявление фабричного метода мы перешли от объекта, создающего экземпляры конкретных классов, к набору классов, решающих ту же задачу. Вся ответственность за создание экземпляров Pizza перемещена в метод, действующий как фабрика. Фабричный метод отвечает за создание объектов и инкапсулирует эту операцию в субклассе. Клиентский код в суперклассе отделяется от кода создания объекта в субклассе. abstract Product factoryMethod(String type);


Слайд 16

17 Оформление заказа пиццы Для начала Наччи и Маччи понадобятся экземпляры субклассов PizzaStore. Наччи создает экземпляр ChicagoPizzaStore, а Маччи — экземпляр NYPizzaStore. Имея экземпляр PizzaStore, Наччи и Маччи вызывают метод orderPizza() и передают ему тип нужной пиццы (вегетарианская, с сыром и т. д.). Для создания объекта вызывается метод createPizza(), который определяется в двух субклассах: NYPizzaStore и ChicagoPizzaStore. В любом случае методу orderPizza() возвращается экземпляр Pizza. Метод orderPizza() не знает, какая разновидность пиццы была создана, но знает, что это именно пицца. Соответственно, он готовит, выпекает, нарезает и упаковывает пиццу для Наччи и Маччи. Реализация (Factory Method)


Слайд 17

18 Диаграмма классов


Слайд 18

19 Определение паттерна Фабричный Метод Фабричный Метод определяет интерфейс создания объекта, но позволяет субклассам выбрать класс создаваемого экземпляра. Делегирует операцию создания экземпляра субклассам


Слайд 19

20 Зависимости между объектами


Слайд 20

21 Инверсия зависимостей Полезный принцип проектирования этот принцип сильно напоминает принцип «Программируйте на уровне интерфейсов, а не на уровне реализаций» НО принцип инверсии зависимостей предъявляет еще более жесткие требования к абстракции. Он требует, чтобы высокоуровневые компоненты не зависели от низкоуровневых компонентов; вместо этого и те, и другие должны зависеть от абстракций.


Слайд 21

22 Применение принципа Инверсия зависимостей достигается за счет использования Фабричного Метода Проектирование от частного к общему (абстрагирование)


Слайд 22

23 Советы по применению принципа Ссылки на конкретные классы не должны храниться в переменных. В архитектуре не должно быть классов, производных от конкретных классов. Методы не должны переопределять методы, реализованные в каких-либо из его базовых классов. Если класс с большой вероятностью останется неизменным, в создании экземпляра конкретного класса не будет ничего страшного. Если класс с большой вероятностью будет изменяться, в вашем распоряжении хорошие способы инкапсуляции таких изменений, например Фабричный Метод


Слайд 23

24 Семейства ингредиентов Пиццы делаются из одних компонентов, но в разных регионах используются разные реализации этих компонентов Каждое семейство состоит из типа основы, типа сыра, типа соуса и др. Каждый регион реализует полное семейство ингридиентов Что нужно сделать Построить фабрику ингредиентов для каждого региона. Для этого мы создадим субкласс PizzalngredientFactory, реализующий все методы create. Реализовать набор классов ингредиентов, которые будут использоваться с фабрикой, — ReggianoCheese, RedPeppers, ThickCrustDough и т. д. Там, где это возможно, эти классы могут использоваться совместно несколькими регионами. Затем все новые классы необходимо связать воедино. Для этого мы определим новые фабрики ингредиентов в коде PizzaStore. Реализация (factory)


Слайд 24

25 Применение фабрики Код Pizza использует фабрику для производства ингредиентов, которые определяются используемой фабрикой. Класс Pizza работает с обобщенными ингредиентами, без учета их региональных различий. Этот класс работает со всеми фабриками ингредиентов. sauce = ingredientFactory.createSauce();


Слайд 25

26 Достигнутый результат Реализован механизм создания семейств ингредиентов для пиццы (для чего введен новый тип фабрики «Абстрактная фабрика») Выделены обобщенные ингредиенты Абстрактная фабрика определяет интерфейс создания семейств продуктов, что отделяет код использования продуктов от кода создания. Для каждого контекста создается конкретная фабрика, реализующая интерфейс абстрактной фабрики (создают одинаковые продукты, но с разной реализацией) Отделение кода использования от кода создания конкретных продуктов позволяет переключать фабрики динамически (в процессе выполнения) для изменения поведения


Слайд 26

27 Оформление заказа пиццы Сначала создается объект NYPizzaStore. Имея экземпляр PizzaStore, Наччи и Маччи вызывают метод orderPizza() и передают ему тип нужной пиццы (вегетарианская, с сыром и т. д.). Для создания объекта вызывается метод createPizza() и методу orderPizza() возвращается экземпляр Pizza. При вызове метода createPizza() вступает в дело фабрика ингредиентов. При вызове метода prepare() фабрика получает запрос на создание ингредиентов Метод orderPizza() выпекает, нарезает и упаковывает приготовленную пиццу.


Слайд 27

28 Определение паттерна Абстрактная Фабрика Абстрактная Фабрика предоставляет интерфейс создания семейств, взаимосвязанных или взаимозависимых объектов без указания их конкретных классов


Слайд 28

29 Сравнение Абстрактной Фабрики и Фабричного Метода Методы Абстрактной Фабрики часто реализуются как фабричные методы. Абстрактная Фабрика и Фабричный Метод инкапсулируют создание объектов, чтобы обеспечить слабую связанность приложений и снизить зависимость от реализаций, но делают это по-разному. Фабричный Метод для создания использует классы (наследование), а Абстрактная Фабрика — объекты (композиция). Суть паттерна Фабричный Метод заключается в использовании субкласса, который создает объекты за вас (отделяет клиентов от конкретных типов). Абстрактная Фабрика предоставляет абстрактный тип для создания семейств продуктов. Интерфейс изменяется при добавлении новых продуктов. Используйте Абстрактную Фабрику при создании семейств продуктов, когда вы должны обеспечить логическую согласованность создаваемых объектов. Фабричный Метод будет полезен для отделения клиентского кода от создания экземпляров конкретных классов и в тех ситуациях, когда точный состав всех конкретных классов неизвестен заранее.


Слайд 29

30 Резюме Концепции ООП Абстракция Инкапсуляция Полиморфизм Наследование Стратегия определяет семейство алгоритмов, инкапсулирует каждый из них и обеспечивает их взаимозаменяемость. Он позволяет модифицировать алгоритмы независимо от их использования на стороне клиента. Наблюдатель определяет отношение «один-ко-многим» таким образом, что при изменений состояния одного объекта происходит автоматическое оповещение и обновление всех зависимых объектов. Декоратор динамически наделяет объект новыми возможностями и является гибкой альтернативой субклассированию в области расширения функциональности. Фабричный метод определяет интерфейс создания объекта, но позволяет субклассам выбрать создаваемый экземпляр. Принципы Инкапсулируйте, то что изменяется Отдавайте предпочтение композиции перед наследованием Программируйте на уровне интерфейсов, а не реализации Стремитесь к слабой связности взаимодействующих объектов Классы должны быть открыты для расширения, но закрыты для изменения Код должен зависеть от абстракций, а не от конкретных классов. Абстрактная фабрика предоставляет интерфейс для создания семейств взаимосвязанных объектов без указания их конкретных классов.


Слайд 30

31 Ключевые моменты Все фабрики инкапсулируют создание объектов. Простая Фабрика, хотя и не является полноценным паттерном, обеспечивает простой механизм изоляции клиентов от конкретных классов. Фабричный Метод основан на наследовании: создание объектов делегируется субклассам, реализующим фабричный метод для создания объектов. Абстрактная Фабрика основана на композиции: создание объектов реализуется в методе, доступ к которому осуществляется через интерфейс фабрики. Все фабричные паттерны обеспечивают слабую связанность за счет сокращения зависимости приложения от конкретных классов. Задача Фабричного Метода — перемещение создания экземпляров в субклассы. Задача Абстрактной Фабрики — создание семейств взаимосвязанных объектов без зависимости от их конкретных классов


×

HTML:





Ссылка: