Stáhnout prezentaci
Prezentace se nahrává, počkejte prosím
ZveřejnilRůžena Dostálová
1
Factory Method
2
Motivace – tisk Knihovna tiskne dokumenty do pdf File Open() Close() Print() PresentationWritingDrawing Knihovna tiskne obrázky do pdf JPEGGIFBMPFile Open() Close() Print()
3
public class Printer { public File printToPDF(String path) { File file; file = new Presentation, Writing or Drawing? file.Load(); file.Print(); file.Close(); return file; } Motivace – tisk Jak získáme tu správnou třídu k instanciování? Jak implementovat metodu printToPDF? Rozhodujeme se na základě přípony souboru
4
public class Printer { public File printToPDF(String path) { File file; if(ext(path) == "ppt") file = new Presentation(path); else if(ext(path) == "doc") file = new Writing(path); else if(ext(path) == "drw") file = new Drawing(path); file.Load(); file.Print(); file.Close(); return file; } Rychlé řešení Komplikace Tisk obrázků místo dokumentů Možné duplicity kódu Přidání nového typu dokumentu (např. Excel) Rozhodnutí přímo v těle metody Potřebuje metoda znát potomky třídy File? Co když přidáme novou třídu Excel?
5
public class Printer { public abstract File CreateFile(string path); public void printToPDF(String path) { File file = this.CreateFile(path); file.Load(); file.Print(); file.Close(); } Factory Method – řešení public class ImagePrinter : Printer { public override File CreateFile(string path) { if(ext(path) == "jpeg") return new Jpeg(path); else if(ext(path) == "gif") return new Gif(path); return null; } public class DocumentPrinter : Printer { public override File CreateFile(string path) { if(ext(path) == "ppt") return new Presentation(path); else if(ext(path) == "doc") return new Writing(path); return null; } Knihovna pro tisk dokumentů Knihovna pro tisk obrázků Výhoda - zapouzdření
6
public class Printer { public abstract File CreateFile(string path); public void printToPDF(String path) { File file = this.CreateFile(path); file.Load(); file.Print(); file.Close(); } Factory Method – řešení 2.0 public class ImagePrinter : Printer { public override File CreateFile(string path) { if(ext(path) == "jpeg") return new Jpeg(path); else if(ext(path) == "gif") return new Gif(path); return base.CreateFile(path); } public class DocumentPrinter : Printer { public override File CreateFile(string path) { if(ext(path) == "ppt") return new Presentation(path); else if(ext(path) == "doc") return new Writing(path); return base.CreateFile(path); } Knihovna pro tisk dokumentů Knihovna pro tisk obrázků
7
Motivace 2 – hra public class Game { public Room GenerateRoom() { Room room = new Room(); room.add(new Door()); int monsters = random(0,5); for(int i = 0; i < monsters; ++i) { room.add(new Monster()); } Metoda generuje místnosti ve hře Chceme přidat novou třídu AdvancedMonster Jak ji integrovat do hry?
8
Factory Method – řešení public class Game { public virtual Room CreateRoom() { return new Room(); } public virtual Door CreateDoor() { return new Door(); } public virtual Monster CreateMonster() { return new Monster(); } public Room GenerateRoom() { Room room = this.CreateRoom(); room.add(this.CreateDoor()); int monsters = random(0,5); for(int i = 0; i < monsters; ++i) { room.add(this.CreateMonster()); } return room; } Delegujeme instanciování na dedikované metody public class HardGame : Game { public override Monster CreateMonster() { return new AdvancedMonster(); }
9
Struktura Účastníci Product ( File ) definuje rozhraní objektů vytvářených tovární metodou ConcreteProduct ( Presentation ) implementuje rozhraní Productu Creator ( Printer ) deklaruje tovární metodu vracející objekt typu Product může definovat defaultní implementaci vracející defaultní objekt ConcreteProduct ConcreteCreator ( DocumentPrinter ) implementuje tovární metodu vracející instanci ConcreteProductu Factory Method – struktura
10
Factory Method – přehled Známý jako Tovární metoda nebo Virtual Constructor Kategorie Creational design patterns Účel Definuje rozhraní pro vytvoření objektu Odložení instanciace na potomka Potomci sami rozhodují, kterou třídu instanciovat Obecné podmínky Třída nezná konkrétní potomky Delegace instanciace na jedno místo + zapouzdření Potřeba lifetime managementu na centrálním místě Praktické situace Framework pro více využití => Document, Image Nahrazení využívaných tříd jejich potomky => AdvancedMonster Rozšíření aplikace o nové třídy => Excel, HillSlotCarPiece Testování
11
Propojení paralelních hierarchií tříd třída deleguje některé akce na jinou třídu příklad: manipulovatelné grafické objekty (úsečka, obdélník,...) stav manipulace udržován pouze během manipulace - ne u grafického objektu manipulace různých objektů uchovávají různý stav (koncový bod, rozteč řádků,...) objekt Manipulator, konkrétní grafické objekty mají vlastní manipulátory Figure deklaruje CreateManipulator, potomci vytvářejí vlastní manipulátory částečně paralelní hierarchie - dědění defaultního manipulátoru Factory Method – paralelní hierarchie
12
Factory Method – static factory method public class Complex { public double real; public double imaginary; public static Complex FromCartesian(double real, double imaginary) { return new Complex(real, imaginary); } public static Complex FromPolar(double modulus, double angle) { return new Complex(modulus * Cos(angle), modulus * Sin(angle)); } private Complex(double real, double imaginary) { this.real = real; this.imaginary = imaginary; } Když už není možné přetížit konstruktory Nevýhody Bez privátních nebo protected konstruktorů nelze vytvářet potomky Creatora Výhody Není nutné vždy vytvářet novou instanci Lze vracet jakéhokoliv potomka
13
Factory Method – testování Komunikační framework třída Client potomek DangerousClient Automatické testování bezpečnosti potřeba automaticky podstrčit třídu DangerousClient Řešení vzor Factory Method pro třídu Client
14
Factory Method – implementace Implementace dvě hlavní varianty Creator je abstraktní třída (nebo interface) nutnost dědičnosti a vlastní implementace Creator je standardní třída => defaultní implementace flexibilita parametrizované tovární metody variace - více druhů produktů metoda dostane parametr identifikující druh objektu (ProdId) všechny objekty sdílejí jedno rozhraní - Product class Creator { public: virtual Prod* Create(ProdId); }; Prod* Creator::Create (ProdId id) { if(id==MINE) return new MyProd; if(id==YOURS) return new YourProd; return 0; } Prod* MyCreator::Create (ProdId id) { if(id==MINE) return new MyProd2; if(id==THEIRS) return new TheirProd; return Creator::Create(id); } Obsluha ostatních id se deleguje na předka
15
Factory Method – implementace použití šablon někdy zbytečné vytvářet další potomky šablona parametrizovaná Produktem není zapotřebí vytvářet potomky class Creator { public: virtual Product* CreateProduct() = 0; }; template class StdCreator: public Creator { public: virtual Product* CreateProduct(); }; template Product* StdCreator ::CreateProduct() { return new T; } class MyProduct : public Product { public: MyProduct(); //... }; StdCreator myCreator; vrací konkrétního potomka abstraktního produktu
16
Factory Method – příklady použití virtual Qmenu* QmainWindow::createPopupMenu() Qt gui framework (C++) Java API – XML parsery, DateFormat třída DocumentBuilderFactory, DocumentBuilder SAXParserFactory, SAXParser Zend webový aplikační framework (PHP) Třída Zend_Db – connector k různým typům databází // require_once 'Zend/Db/Adapter/Pdo/Mysql.php'; // Automatically load class Zend_Db_Adapter_Pdo_Mysql // and create an instance of it. $db = Zend_Db::factory('Pdo_Mysql', array( 'host' => '127.0.0.1', 'username' => 'webuser', 'password' => 'xxxxxxxx', 'dbname' => 'test' )); Factory method Pdo_Sqlite, Pdo_Mssql, Oracle, DB2,... DateFormat df1 = DateFormat.getDateInstance(DateFormat.FULL, Locale.FRANCE); Factory method
17
Factory Method – příklady použití public static function factory($adapter, $config = array()) { // obtaining adapter class name $adapterName = strtolower($adapterNamespace. '_'. $adapter); // Load the adapter class. This throws an exception // if the specified class cannot be loaded. @Zend_Loader::loadClass($adapterName); // Create an instance of the adapter class. // Pass the config to the adapter class constructor. $dbAdapter = new $adapterName($config); // Verify that the object created is // a descendent of the abstract adapter type. if (! $dbAdapter instanceof Zend_Db_Adapter_Abstract) { // throwing Zend_Db_Exception require_once 'Zend/Db/Exception.php'; throw new Zend_Db_Exception("Adapter class '$adapterName' does not “ “extend Zend_Db_Adapter_Abstract"); } return $dbAdapter; } Factory method Concrete Product test of Product base class
18
Factory Method – výhody a nevýhody Výhody Oddělení vrstev Odstraní nutnost používat aplikačně-specifické třídy Možnost definovat vlastní ConcreteProduct Propojení paralelních tříd Jasně určí, které třídy patří k sobě Nevýhody Nutnost vytvořit potomka Vytváření potomka Creator pouze kvůli instanci ConcreteProduct Nevadí pokud klient musí vždy vytvořit potomka
19
Factory Method - související návrhové vzory Shrnutí flexibilita za relativně malou cenu obvyklá základní metoda zvýšení flexibility virtual constructor časté využití jinými vzory Abstract Factory často implementovaná pomocí továrních metod Template Method často volány tovární metody Prototype nevyžaduje dědění Creatora ... avšak vyžaduje navíc inicializaci produktové třídy (např. Clone())
Podobné prezentace
© 2024 SlidePlayer.cz Inc.
All rights reserved.