1 SW_07 Návrhový vzor: Továrna - Factory 1. Jednoduchá továrna - Simple Factory 2. Tovární metoda - Factory Method 3. Abstraktní továrna - Abstract Factory
Vzor Továrna - Factory 2 Kontext: při vytváření třídy obyčejně doplníme konstruktory na tvorbu instancí, Problém: někdy klient potřebuje nový objekt, ale neví, od které z několika možných tříd (hierarchie) vytvořit instanci, metoda new není špatná, je ale problémem při změnách rozšiřování funkčnosti (přidávání dalších podtříd).
Vzor Továrna - Factory 3 Řešení: vzor Továrna ukládá všechny proměnné aspekty spojené s tvorbou instancí do třídy Továrna nebo jejich podtříd a vytváří tak instance požadovaných tříd. Klient je odcloněn od tvorby konkrétních instancí. Rozlišujeme tři formy vzoru Továrna, a to 1. jednoduchá továrna, 2. tovární metoda, 3. abstraktní továrna.
Outline 4 Kachna kachna = new DivokaKachna(); Programování proti rozhraní. Kachna kachna; if(piknik) { kachna = new DivokaKachna(); else if (myslivost) { kachna = new KachniVabnicka(); else if (koupani) { kachna = new GumovaKachna(); Existuje řada různých kachen k různému použití. Podle toho chceme vytvářet instanci dané kachny.
Metoda new 5 Metoda new (vytvoření instance) je pevně spojena s konkrétní třídou. Programový návrh by měl být otevřený pro rozšiřování (přidávání dalších tříd), ale také blízký pro modifikaci. Programování proti rozhraní. Způsob řešení: identifikace aspektů, které se mění jejich oddělení od zbytku neměnné aplikace.
Outline 6 Pizza orderpizza() { Pizza pizza; Pizza pizza = new Pizza() (); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; Identifikace aspektů, které se mění. Třída Pizza by měla být kvůli flexibilitě rozhraním, nebo abstraktní třídou Nedostatek: potřebujeme více než pouze jeden typ pizzy
Outline 7 Pizza orderpizza(string type) { Pizza pizza = null; Možnost změnit typ pizzy 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(); část, která se mění další typy v závislosti na typu se vytváří konkrétní instance pizzy pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; část, která zůstává stejná
Zapouzdření objektu vytváření instancí 8 Vytvoříme novou třídu, do které uložíme původní část kódu z metody orderpizza(). Tuto novou třídu nazveme Factory továrna. Obecně Factories (továrny)se zabývají detaily vytváření objektů. Tím máme SimplePizzaFactory kdykoli chceme další objekt (instanci), požádáme pizza factory o nový objekt.
public class SimplePizzaFactory { Outline 9 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;
PizzaStore obchod s pizzou 10 Obchod s pizzou (PizzaStore) tvoří klientský kód (kód klienta). Factory (továrna) nám vytvoří požadovanou pizzu.
1. Simple Factory 11 Simple Factory je spíše idiomem, než návrhovým vzorem.
abstract public class Pizza { String name; String dough; String sauce; ArrayList toppings = new ArrayList(); Outline 12 public String getname() { return name; public void prepare() { System.out.println("Preparing " + name); public void bake() { System.out.println("Baking " + name); public void cut() { System.out.println("Cutting " + name); public void box() { System.out.println("Boxing " + name);
Outline 13 public class CheesePizza extends Pizza { public CheesePizza() { name = "Cheese Pizza"; dough = "Regular Crust"; sauce = "Marinara Pizza Sauce"; toppings.add("fresh Mozzarella"); toppings.add("parmesan"); Specializovanější třídy třídy Pizza.
public class SimplePizzaFactory { Outline 14 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; Odkaz na pizzu Programování proti rozhraní.
public class PizzaStore { SimplePizzaFactory factory; // konstruktor public PizzaStore(SimplePizzaFactory factory) { this.factory = factory; Klient Outline odkaz na factory 15 public Pizza orderpizza(string type) { Pizza pizza; pizza = factory.createpizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza;
Outline 16 public class PizzaTestDrive { public static void main(string[] args) { SimplePizzaFactory factory = new SimplePizzaFactory(); PizzaStore store = new PizzaStore(factory); Aplikace Odkaz na factory Pizza pizza = store.orderpizza("cheese"); System.out.println("We ordered a " + pizza.getname() + "\n"); " pizza = store.orderpizza("veggie"); System.out.println("We ordered a " + pizza.getname() + "\n"); "
Jednoduchá továrna 17 Existuje jen jeden typ továrny, tedy pouze jedna třída Tovarna. Existuje pouze jeden produkt (pizza), který je dále specifikovaný do různých druhů pizz. Třída PizzaStore představuje klienta.
Rozšiřování obchodů s pizzou 2. Factory Method 18 Potřebujeme mít různé typy továren vytvářející jeden produkt dále specializovaný. Chceme rozšířit obchody např. NY, Chicago. Každý regionální obchod může mít odlišnosti v nabídce stylů pizzy (NY, Chicago, California) mají odlišné možnosti. Chceme, aby regionální obchody byly ovlivněny kódem PizzaStore pizzy jsou připravovány stejným způsobem.
Možný přístup 19 Vyjdeme z SimplePizzaFactory a vytvoříme tři odlišné factories: NYPizzaFactory, ChicagoPizzaFactory, CalifirniaPizzaFactory.
Outline 20 NYPizzaFactory nyfactory = new NYPizzaFactory(); PizzaStore nystore = new PizzaStore(nyFactory nyfactory); nystore.order( Cheese ); ChicagoPizzaFactory chicagofactory = new ChicagoPizzaFactory(); PizzaStore chicagostore = new PizzaStore(chicagoFactory chicagofactory); chicagostore.order( Cheese ); vytvoření factory pro přípravu NY pizza stylu vytvoření PizzaStore a předání odkazu na factory objednání pizzy v NY stylu
Zvýšení řízení kvality 21 Myšlenka SimpleFactory je, že koncesní obchody (franchize) využívají factory k výrobě instancí, ale již např. používají jiné krabice box() a zapomínají krájet pizzu cut(). Nutnost vytvoření frameworku, který sváže Nutnost vytvoření frameworku, který sváže pevněji jednotlivé obchody s pizzou, ale stále zachová pružnost (flexibilitu).
Framework pro obchody s pizzou 22 Existuje cesta, jak soustředit všechny aktivity vytváření pizzy do třídy PizzaStore a nechat frameworku prostor pro regionální styl prodejen. Postup: createpizza() přijde zpět do třídy PizzaStore, ale jako abstraktní metoda. pro regionální styly se vytvoří podtřídy od třídy PizzaStore.
public abstract class PizzaStore { Outline 23 public Pizza orderpizza(string type) { Pizza pizza = createpizza(type); System.out.println("--- Making a " + pizza.getname() + " ---"); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; abstract Pizza createpizza(string item);
Podtřídy mohou rozhodovat 24 public Pizza createpizza(string item) { if (item.equals("cheese")) { return new ChicagoStyleCheesePizza(); else if (item.equals("veggie")) { return new ChicagoStyleVeggiePizza(); else if (item.equals("clam")) { return new ChicagoStyleClamPizza(); else if (item.equals("pepperoni")) { return new ChicagoStylePepperoniPizza(); else return null;
Metody createpizza() a orderpizza() 25 Metoda orderpizza() je definovaná v abstraktní třídě PizzaStore, ale konkrétně je dotvořena v podtřídách. Metoda orderpizza() volá metodu createpizza(), aby skutečně dostala objekt pizza. Metoda orderpizza() nemůže vytvořit objekt pizza, protože neví jak. Když orderpizza() volá createpizza(), jedna z podtříd PizzaStore to provede.
Úprava třídy PizzaStore 26 Všechny podtřídy třídy PizzaStore (regionální obchody) musí doplnit metodu createpizza(), která implementuje jejich (regionální styl) pizzy.
Outline 27 public class NYPizzaStore extends PizzaStore { Pizza createpizza(string item) { if (item.equals("cheese")) { return new NYStyleCheesePizza(); else if (item.equals("veggie")) { return new NYStyleVeggiePizza(); else if (item.equals("clam")) { return new NYStyleClamPizza(); else if (item.equals("pepperoni")) { return new NYStylePepperoniPizza(); else return null;
Deklarace factory metody (2) 28 public abstract class PizzaStore public Pizza orderpizza(string type) { Pizza pizza; pizza = createpizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; protected abstract Pizza createpizza(string item); // abstraktní metoda abstract Product factorymethod(string type) podtřídy vytváří konkrétní objekt, metoda vrací Produkt, který je využit v nadtřídě, metoda factory izoluje klienta od znalosti, jaký druh konkrétního produktu je vytvářen (instancionován), metoda factory může mít parametry pro specifikaci vytvářeného produktu.
PizzaStore nypizzastore = new NYPizzaStore(); nypizzastore.orderpizza( cheese ); Outline Postup při objednávání: 29 Pizza pizza = createpizza( cheese ); orderpizza() volá createpizza() pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box();
public abstract class Pizza { String name; String dough; String sauce; ArrayList toppings = new ArrayList(); void prepare() { System.out.println("Preparing " + name); System.out.println("Tossing dough..."); System.out.println("Adding sauce..."); System.out.println("Adding toppings: "); for (int i = 0; i < toppings.size(); i++) { System.out.println(" " + toppings.get(i)); Outline Musíme doplnit třídu Pizza 30 void bake() { System.out.println("Bake for 25 minutes at 350"); void cut() { System.out.println("Cutting the pizza into diagonal slices"); void box() { System.out.println("Place pizza in official PizzaStore box"); public String getname() { return name;
public class NYStyleCheesePizza extends Pizza { public NYStyleCheesePizza() { name = "NY Style Sauce and Cheese Pizza"; dough = "Thin Crust Dough"; sauce = "Marinara Sauce"; Outline podtřída třídy Pizza 31 toppings.add("grated Reggiano Cheese");
public class PizzaTestDrive { public static void main(string[] args) { PizzaStore nystore = new NYPizzaStore(); PizzaStore chicagostore = new ChicagoPizzaStore(); Pizza pizza = nystore.orderpizza("cheese"); System.out.println("Ethan ordered a " + pizza.getname() + "\n"); " pizza = chicagostore.orderpizza("cheese"); System.out.println("Joel ordered a " + pizza.getname() + "\n"); " Preparing NY Style Sauce and Cheese Pizza Tossing dough... Adding sauce... Adding toppings: Grated Reggiano Cheese Bake for 25 minutes at 350 Cutting the pizza into diagonal slices Place pizza in official PizzaStore box Ethan ordered a NY Style Sauce and Cheese Pizza Outline Klient hlavní program a výpis 32 Preparing Chicago Style Deep Dish Cheese Pizza Tossing dough... Adding sauce... Adding toppings: Shredded Mozzarella Cheese Bake for 25 minutes at 350 Cutting the pizza into square slices Place pizza in official PizzaStore box Joel ordered a Chicago Style Deep Dish Cheese Pizza
Vzor Factory (Továrna) 33 Všechny vzory Factory zapouzdřují vytváření objektu. Metoda Factory zapouzdřuje vytváření objektu tím, že nechá na podtřídě, aby rozhodla, který objekt vytvoří. Rozlišujeme třídy pro vytváření Factory a třídy vlastního produktu - Pizza.
Třídy vytváření a třídy produktu 34
Paralelní hierarchie 35
Simple Factory 36 Jednoduchá továrna (Simple Factory) a tovární metoda (Factory Method)
public abstract class PizzaStore { Outline 37 abstract Pizza createpizza(string item); public Pizza orderpizza(string type) { Pizza pizza = createpizza(type); System.out.println("--- Making a " + pizza.getname() + " ---"); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; PizzaStore je abstraktní třída s abstraktní metodou createpizza()
public class NYPizzaStore extends PizzaStore { Outline 38 Pizza createpizza(string item) { if (item.equals("cheese")) { return new NYStyleCheesePizza(); else if (item.equals("veggie")) { return new NYStyleVeggiePizza(); else if (item.equals("clam")) { return new NYStyleClamPizza(); else if (item.equals("pepperoni")) { return new NYStylePepperoniPizza(); else return null;
public class PizzaTestDrive { Outline 39 public static void main(string[] args) { PizzaStore nystore = new NYPizzaStore(); PizzaStore chicagostore = new ChicagoPizzaStore(); Pizza pizza = nystore.orderpizza("cheese"); System.out.println("Ethan ordered a " + pizza.getname() + "\n"); " pizza = chicagostore.orderpizza("cheese"); System.out.println("Joel ordered a " + pizza.getname() + "\n"); " pizza = nystore.orderpizza("clam"); System.out.println("Ethan ordered a " + pizza.getname() + "\n"); " pizza = chicagostore.orderpizza("clam"); System.out.println("Joel ordered a " + pizza.getname() + "\n"); "
Definice vzoru tovární metoda Factory method 40 Návrhový vzor tovární metoda (factory method) definuje rozhraní pro vytvoření objektu, ale nechává na podtřídách implementujících toto rozhraní aby rozhodly, která třída vytvoří objekt (instanci). Tovární metoda tedy odkládá proces instanciace na podtřídu.
Tovární metoda Factory Method 41 Product = Pizza; ConcreteProduct = NYStyleCheesePizza; Creator = PizzaStore; factorymethod() = createpizza(); ConcreteCreator = NYPizzaStore factorymethod() = createpizza();
Factory Method tovární metoda 42 Tovární metoda je výhodná pokud existuje jeden konkrétní tvůrce (kreátor), protože implementace produktu je oddělena od jeho použití. Pokud přidáte další produkty, nebo změníte implementaci produktu, kreátor to neovlivní. Tovární metodu jsme implementovali jako parametrickou (parametr ovlivňuje typ instance). Tovární metoda však může vytvářet pouze jeden typ instance.
Tovární metoda 43 K omezení chyb při předávání parametru (projeví se jako run time error) je možné místo typu (String) využívat enum (výčtový typ). Simple factory nemá podtřídy na rozdíl od Simple factory nemá podtřídy na rozdíl od factory method.
Tovární metoda 44 Řešení: Tovární metoda umožňuje tvůrci tříd definovat rozhraní pro vytvářený objekt, zatímco si ponechává volbu, ze které třídy instanci vytvoří.
Klasický příklad použití: Iterátor 45 Vzor Iterátor poskytuje způsob zpřístupnit sekvenčně prvky kolekce Při vytváření instancí Iterátorů je použita metoda Factory V rozhraní Collection je metoda V rozhraní Collection je metoda iterator(), kterou pak implementují všechny třídy kolekcí. Metoda iterator() izoluje toho, kdo ji volá od povědomí, od které vlastně třídy vytváří instanci.
public class ShowIterator { public static void main(string[] args) { List list = Arrays.asList( new String[] { "fountain", "rocket", "sparkler" ); Outline 46 Iterator iter = list.iterator(); while (iter.hasnext()) System.out.println(iter.next()); // Uncomment the next line to see the iterator's actual class: // System.out.println(iter.getClass().getName());
Rozpoznání Metody Factory 47 mylná domněnka, že každá metoda která vytváří a vrací objekt je metoda Factory, v OOP je běžné, že metody vrací nový objekt, fakt, že metoda vytváří nový objekt nemusí znamenat, že je příkladem metody Factory, metoda Factory je metoda, která jednak vytváří nový objekt a dále izoluje klienta od povědomí, od které třídy vytváří objekt, při požadavku na objekt, je definitivní třída objektu, který bude vytvořen závislá na chování objektu Factory, který dostal požadavek na vytvoření nového objektu.
Problémy návrhu další rozšiřování 48 potřebujeme zavést další třídu CaliforniaStylePizzaStore.
Závislosti a inverzní princip závislosti 49 Pro vysvětlení se posuneme zpět; neznáme OO factories a vše řešíme v jednom objektu.
public class DependentPizzaStore { Outline 50 public Pizza createpizza(string style, String type) { Pizza pizza = null; if (style.equals("ny")) { if (type.equals("cheese")) { pizza = new NYStyleCheesePizza(); else if (type.equals("veggie")) { pizza = new NYStyleVeggiePizza(); else if (type.equals("clam")) { pizza = new NYStyleClamPizza(); else if (type.equals("pepperoni")) { pizza = new NYStylePepperoniPizza(); else if (style.equals("chicago")) { if (type.equals("cheese")) { pizza = new ChicagoStyleCheesePizza(); else if (type.equals("veggie")) { pizza = new ChicagoStyleVeggiePizza(); else if (type.equals("clam")) { pizza = new ChicagoStyleClamPizza(); else if (type.equals("pepperoni")) { pizza = new ChicagoStylePepperoniPizza();
else { System.out.println("Error: invalid type of pizza"); Outline 51 return null; pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza;
Závislosti objektů 52 Všechny objekty se vytváří v rámci třídy PizzaStore, místo delegování na factory. Každý nový druh pizzy, vytváří další závislost na PizzaStore. Každá změna konkrétní implementace pizzy, ovlivňuje PizzaStore. PizzaStore závisí na implementaci Pizzy.
Princip inverzní závislosti (The Dependency Inversion Principle) 53 Obecně snížení závislostí konkrétních tříd v programovém kódu je záslužná věc. Princip návrhu (Design Principle): Buď závislý na abstrakcích. Nebuď závislý na konkrétních třídách. Je to podobné jako: Programování k rozhraní, ne k implementaci.
Princip inverzní závislosti (The Dependency Inversion Principle) 54 Princip inverzní závislosti však vytváří silnější tvrzení o abstrakci: Předpokládá, že naše vysoko úrovňové komponenty by neměly být závislé na nízko úrovňových komponentách; obojí by měly spíše záviset na abstrakcích (rozhraní, abstraktní třídy). Vysoko úrovňová komponenta: je třída, s chováním definovaným pomocí nízko úrovňových komponent. Např. PizzaStore vysoko úrovňová komponenta; její chování je definované v pojmech pizza (vytváří všechny druhy pizz)
Princip inverzní závislosti (The Dependency Inversion Principle) 55 Třída PizzaStore je závislá na konkrétních třídách pizza (nízko úrovňové komponenty). Princip říká, být závislý na abstrakcích, jak pro vysokoúrovňové, tak nízko úrovňové komponenty (high level components, low level components).
Princip inverzní závislosti (The Dependency Inversion Principle) 56 Pizza bude abstraktní třída. PizzaStore ( high level component ) nyní závisí na abstraktní třídě. Konkrétní podtřídy od třídy Pizza ( low level components ) jsou závislé na abstraktní třídě Pizza také. Metoda factory není jedinou technikou, která se řídí inverzním principem závislosti, ale je jedna z výkonných technik.
Princip inverzní závislosti (The Dependency Inversion Principle) 57 Inverzní princip je zde proto, protože obracíme typický způsob myšlení o OO návrhu. Nízko-úrovňové komponenty závisí na abstrakci vyšší úrovně. Vysoko-úrovňové komponenty jsou svázány se stejnou abstrakcí. Závislost top-bottom se změnila. Komponenty high-level a low-level jsou závislé na stejné úrovni abstrakce.
Jak nezapomenout na princip 58 O tvorbu konkrétních objektů třídy Pizza se bude starat factory. Žádná proměnná by neměla odkazovat na konkrétní třídu. použití new vede k odkazu na konkrétní třídu, je třeba použít factory, Žádná třída by se neměla odvozovat od konkrétní třídy. pokud vytváříte podtřídu, jste závislý na nadtřídě; je lépe vytvářet podtřídu od abstraktní třídy nebo rozhraní.
Jak nezapomenout na princip 59 Žádná metoda by neměla předeklarovat (overrride) implementovanou metodu základních tříd. myslí se tím metodu abstraktní třídy (např. Pizza). Je to jen pomůcka, kterou ne vždy můžeme Je to jen pomůcka, kterou ne vždy můžeme dodržet.
Rozšiřování návrhu 3. Abstract Factory 60 V původním návrhu třída Pizza obsahovala pouze jeden typ surovin - produktu (těsto, omáčku, sýr ). Tyto základní suroviny se však rozšiřují a specializují. Vzniká rodina ingrediencí. Specializace továren zůstává a přidává se více produktů.
public interface PizzaIngredientFactory { Outline 61 public Dough createdough(); public Sauce createsauce(); public Cheese createcheese(); public Veggies[] createveggies(); public Pepperoni createpepperoni(); public Clams createclam(); Vytváření továren pro ingredience Ingredient factories. Pro každou ingredienci vytváříme konkrétní metodu.
public class NYPizzaIngredientFactory implements PizzaIngredientFactory { public Dough createdough() { return new ThinCrustDough(); public Sauce createsauce() { return new MarinaraSauce(); Outline Vytvoříme factory (továrnu) pro každý region. 62 public Cheese createcheese() { return new ReggianoCheese(); public Veggies[] createveggies() { Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() ; return veggies; public Pepperoni createpepperoni() { return new SlicedPepperoni(); public Clams createclam() { return new FreshClams();
Úpravy třídy Pizza 63 Máme vytvořené factories pro každý region, které dodávají ingredience podle regionu. Nutné úpravy ve třídě Pizza:
public abstract class Pizza { String name; Dough dough; Sauce sauce; Veggies veggies[]; Cheese cheese; Pepperoni pepperoni; Clams clam; abstract void prepare(); void bake() { System.out.println("Bake for 25 minutes at 350"); void cut() { System.out.println("Cutting the pizza into diagonal + slices"); void box() { System.out.println("Place pizza in + official PizzaStore box"); void setname(string name) { this.name = name; String getname() { return name; public String tostring() { // kód který tiskne pizzu Outline 64
Úprava podtříd třídy Pizza 65 Dopracovat použití regionálních ingrediencí. Podtřídy využívají factory k vytváření ingrediencí. sauce = ingredientfactory.createsauce();
public class CheesePizza extends Pizza { PizzaIngredientFactory ingredientfactory; // konktruktor doplňuje odkaz na ingredientfactory public CheesePizza(PizzaIngredientFactory ingredientfactory) { this.ingredientfactory = ingredientfactory; Outline Podobné je to i u dalších tříd. 66 void prepare() { System.out.println("Preparing " + name); dough = ingredientfactory.createdough(); sauce = ingredientfactory.createsauce(); cheese = ingredientfactory.createcheese();
Úprava třídy PizzaStore 67 Potřebujeme přidat reference na jejich lokální továrny ingrediencí.
public class NYPizzaStore extends PizzaStore { Outline 68 protected Pizza createpizza(string item) { Pizza pizza = null; PizzaIngredientFactory ingredientfactory = new NYPizzaIngredientFactory(); if (item.equals("cheese")) { pizza = new CheesePizza(ingredientFactory ingredientfactory); pizza.setname("new York Style Cheese Pizza"); else if (item.equals("veggie")) { pizza = new VeggiePizza(ingredientFactory ingredientfactory); pizza.setname("new York Style Veggie Pizza"); else if (item.equals("clam")) { pizza = new ClamPizza(ingredientFactory ingredientfactory); pizza.setname("new York Style Clam Pizza"); Metoda createpizza() má nastavenou lokální proměnnou ingredientfactory na svoji regionální ingredient factory. Tato proměnná se předává každé pizze aby si mohla vytvořit ingredience. else if (item.equals("pepperoni")) { pizza = new PepperoniPizza(ingredientFactory ingredientfactory); pizza.setname("new York Style Pepperoni Pizza"); return pizza;
Továrny - Factories 69 Abstraktní továrna poskytuje rozhraní pro skupinu (rodinu) různých produktů. Od abstraktní továrny jsou odvozeny konkrétní továrny, které produkují stejné produkty s jinou implementací.
1. Potřebujeme PizzaStore např. NY PizzaStore, PizzaStore nypizzastore = new PizzaStore(); 2. uděláme objednávku, nypizzastore.orderpizza( cheese ); Outline Postup objednání a přípravy pizzy 70 3. metoda orderpizza() nejdříve volá metodu createpizza(), Pizza pizza = createpizza( cheese ); 4. když je vyvolaná metoda createpizza() tehdy je začleněna ingredient factory, Pizza = pizza new CheesePizza(nyIngredientFactory); 5. potřebujeme připravit pizzu; v okamžiku kdy je zavolána metoda prepare(), je požádána factory k přípravě ingrediencí, void prepare() { dough = factory.createdough(); sauce = factory.createsauce(); cheese = factory.createcheese(); 6. konečně je pizza připravena a metoda orderpizza() volá další metody bake(), cut(), boxes().
Vzor 3. Abstract Factory Abstraktní továrna 71 Vzor abstraktní továrna poskytuje rozhraní pro vytváření řady příbuzných nebo závislých objektů bez specifikace jejich konkrétní třídy. Abstraktní továrna dovoluje klientovi používat abstraktní rozhraní k vytváření množiny příbuzných produktů bez znalosti konkrétních produktů, které jsou vytvářeny. Tímto způsobem je klient oddělen od specifikací konkrétních produktů.
Abstraktní továrna 72 Client «interface» AbstractProductA «interface» AbstractFactory createproducta() createproductb() ProductA2 ProductA1 ConcreteFactory1 createproducta() createproductb() ConcreteFactory2 createproducta() createproductb() «interface» AbstractProductB ProductB2 ProductB1
Abstraktní továrna 73 Klient je napsán oproti abstraktní továrně, ale za běhu programu je to doplněno na konkrétní továrnu. Konkrétní továrny implementují různé rodiny produktů. Klient využívá pouze jednu konkrétní továrnu v daném čase. Každá konkrétní továrna může produkovat celou množinu příbuzných produktů.
Abstraktní továrna 74 Pizza prepare() // other methods «interface» Dough «interface» PizzaIngredientFactory createdough() createsauce() createcheese() CreateClams() ThickCrustDough «interface» Sauce ThinCrustDough NYPizzaIngredientFactory ChicagoPizzaIngredientFactory PlumTomatoSauce MarinaraSauce createdough() createsauce() createcheese() CreateClams() createdough() createsauce() createcheese() CreateClams() «interface» Cheese MozzarellaCheese RegglanoCheese «interface» Clams FrozenClams FreshClams
public class PizzaTestDrive { Outline 75 public static void main(string[] args) { PizzaStore nystore = new NYPizzaStore(); PizzaStore chicagostore = new ChicagoPizzaStore(); Pizza pizza = nystore.orderpizza("cheese"); System.out.println("Ethan ordered a " + pizza + "\n"); " pizza = chicagostore.orderpizza("cheese"); System.out.println("Joel ordered a " + pizza + "\n"); " pizza = nystore.orderpizza("clam"); System.out.println("Ethan ordered a " + pizza + "\n"); " pizza = chicagostore.orderpizza("clam"); System.out.println("Joel ordered a " + pizza + "\n"); "
public abstract class PizzaStore { Outline 76 protected abstract Pizza createpizza(string item); public Pizza orderpizza(string type) { Pizza pizza = createpizza(type); System.out.println("--- Making a " + pizza.getname() + " ---"); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza;
public class NYPizzaStore extends PizzaStore { Outline 77 protected Pizza createpizza(string item) { Pizza pizza = null; PizzaIngredientFactory ingredientfactory = new NYPizzaIngredientFactory(); if (item.equals("cheese")) { pizza = new CheesePizza(ingredientFactory ingredientfactory); pizza.setname("new York Style Cheese Pizza"); else if (item.equals("veggie")) { pizza = new VeggiePizza(ingredientFactory ingredientfactory); pizza.setname("new York Style Veggie Pizza"); return pizza;
public interface PizzaIngredientFactory { Outline 78 public Dough createdough(); public Sauce createsauce(); public Cheese createcheese(); public Veggies[] createveggies(); public Pepperoni createpepperoni(); public Clams createclam();
public class NYPizzaIngredientFactory implements PizzaIngredientFactory { Outline 79 public Dough createdough() { return new ThinCrustDough(); public Sauce createsauce() { return new MarinaraSauce(); public Cheese createcheese() { return new ReggianoCheese(); public Veggies[] createveggies() { Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() ; return veggies; public Pepperoni createpepperoni() { return new SlicedPepperoni(); public Clams createclam() { return new FreshClams();
public abstract class Pizza { String name; Outline 80 Dough dough; Sauce sauce; Veggies veggies[]; Cheese cheese; Pepperoni pepperoni; Clams clam; abstract void prepare(); void bake() { System.out.println("Bake for 25 minutes at 350"); void cut() { System.out.println("Cutting the pizza into diagonal slices");...
public class PepperoniPizza extends Pizza { PizzaIngredientFactory ingredientfactory; Outline 81 public PepperoniPizza(PizzaIngredientFactory ingredientfactory) { this.ingredientfactory = ingredientfactory; void prepare() { System.out.println("Preparing " + name); dough = ingredientfactory.createdough(); sauce = ingredientfactory.createsauce(); cheese = ingredientfactory.createcheese(); veggies = ingredientfactory.createveggies(); pepperoni = ingredientfactory.createpepperoni();
public interface Dough { public String tostring(); Outline 82 public class ThickCrustDough implements Dough { public String tostring() { return "ThickCrust style extra thick crust dough";
Jiný příklad Abstraktní továrny 83 GameEnvironment -gameelementfactory -player -obstacle +play() «rozhraní» GameElementFactory +makeplayer() +makeobstacle() «rozhraní» Obstacle +action() Puzzle NastyWeapons KillAndDismember KittiesAndPuzzles +action() +action() +makeplayer() +makeobstacle() +makeplayer() +makeobstacle() «rozhraní» Player +interactwith() Kitty KungFuGuy +interactwith() +interactwith()
Jiný příklad Abstraktní továrny 84 Produkty, které se vytváří: Obstacle, Player. Továrny: KillAndDismember, KitiesAndPuzzles. Klient - GameEnvironment
public interface Obstacle { void action(); Outline 85 public class Puzzle implements Obstacle { @Override public void action() { System.out.println("Puzzle"); public class NastyWeapon implements Obstacle { @Override public void action() { System.out.println("NastyWeapon");
public interface Player { void interactwith(obstacle o); Outline 86 public class KungFuGuy implements Player { @Override public void interactwith(obstacle obstacle) { System.out.print("KungFuGuy now battles a "); obstacle.action(); public class Kitty implements Player { @Override public void interactwith(obstacle obstacle) { System.out.print("Kitty has encountered a "); obstacle.action();
public interface GameElementFactory { Player makeplayer(); Obstacle makeobstacle(); Outline 87
public class KittiesAndPuzzles implements GameElementFactory { @Override public Player makeplayer() { return new Kitty(); Outline 88 @Override public Obstacle makeobstacle() { return new Puzzle();
public class KillAndDismember implements GameElementFactory { Outline 89 @Override public Player makeplayer() { return new KungFuGuy(); @Override public Obstacle makeobstacle() { return new NastyWeapon();
public class GameEnvironment { Outline 90 // tovarna private GameElementFactory factory; // produkty private Player player; private Obstacle obstacle; // konstruktor public GameEnvironment( GameElementFactory factory) { this.factory = factory; player = factory.makeplayer(); obstacle = factory.makeobstacle(); public void play() { player.interactwith(obstacle);
public class Games { public static void main(string[] args) { Outline 91 // ruzne tovarny GameElementFactory kp = new KittiesAndPuzzles(), kd = new KillAndDismember(); // ruzne prostredi GameEnvironment g1 = new GameEnvironment(kp), g2 = new GameEnvironment(kd); g1.play(); g2.play();
Abstraktní továrna 92 Simple factory Factory method Abstract factory. Metody Abstract Factory jsou implementovány jako factory metody. Vzor abstract factory vytváří rodinu příbuzných produktů.