Vzor tovární metody - Factory method pattern
v třídní programování, vzor tovární metody je kreační vzor který používá tovární metody k řešení problému vytváření objektů aniž byste museli přesně specifikovat třída objektu, který bude vytvořen. To se provádí vytvořením objektů voláním tovární metody - buď zadané v rozhraní a implementovány podřízenými třídami nebo implementovány v základní třídě a volitelně přepsán odvozenými třídami - spíše než voláním a konstruktor.
Přehled
Tovární metoda[1]designový vzor je jedním z Návrhové vzory „Gang of Four“ které popisují, jak řešit opakující se konstrukční problémy při navrhování flexibilního a opakovaně použitelného objektově orientovaného softwaru, tj. objektů, které se snadněji implementují, mění, testují a znovu používají.
Namísto konstruktoru běžné třídy se pro zachování v rámci používá vzorový návrh Factory Method PEVNÝ principy programování, oddělení konstrukce objektů od samotných objektů. To má následující výhody a je užitečné mimo jiné v následujících případech:[2]
- Umožňuje konstrukci tříd s komponentou typu, který nebyl předem určen, ale je definován pouze v „rozhraní“ nebo který je definován jako dynamický typ.
- Tedy například třída
Vozidlo
který má členaMotor
rozhraníIMotor
, ale žádný konkrétní typMotor
předem definované, lze sestavit sdělenímVozidlo
konstruktor použítElektrický motor
nebo aBenzínový motor
. TheVozidlo
kód konstruktoru pak zavolá metodu Motor factory, aby vytvořil požadovanýMotor
který je v souladu sIMotor
rozhraní.
- Umožňuje konstrukci podtříd rodiči, jehož typ komponenty nebyl předem určen, ale je definován pouze v rozhraní, nebo který je definován jako dynamický typ.
- Například třída
Vozidlo
se členemMotor
definované s dynamickým typem, může mít podtřídy typuElectricPlane
aStaré auto
každý je konstruován s jiným typem motoru. Toho lze dosáhnout konstrukcí podtříd s tovární metodou vozidla při dodávání typu motoru. V takových případech může být konstruktor skrytý.
- Umožňuje čitelnější kód v případech, kdy existuje více konstruktorů, každý z jiného důvodu.
- Například pokud existují dva konstruktory
Vozidlo (značka: struna, motor: číslo)
aVozidlo (značka: řetězec, vlastník: řetězec, licence: číslo, zakoupeno: datum)
bylo by možné použít čitelnější konstrukci třídVehicle.CreateOwnership (značka: řetězec, vlastník: řetězec, licence: číslo, zakoupeno: datum)
vs.Vehicle.Create (značka: řetězec, motor: číslo)
- Umožňuje třídě odložit instanci na podtřídy a zabránit přímému vytvoření instance objektu typu nadřazené třídy.
- Například Vehicle lze zabránit v instanci přímo, protože nemá žádný konstruktor, a pouze podtřídy jako ElectricPlane nebo OldCar lze vytvořit voláním tovární metody Vehicle (static) v konstruktoru nebo inicializátoru podtřídy.
Vytvoření objektu přímo v rámci třídy, která objekt vyžaduje nebo používá, je nepružné, protože zavazuje třídu k určitému objektu a znemožňuje změnit instanci nezávisle na třídě. Změna instantoru by vyžadovala změnu kódu třídy, které bychom se raději nedotkli. Toto se označuje jako kódová vazba a vzor tovární metody pomáhá oddělení kód.
Návrhový vzor Factory Method se používá nejprve definováním samostatné operace, a tovární metoda, pro vytvoření objektu a jeho následné použití tovární metoda voláním k vytvoření objektu. To umožňuje psaní podtříd, které rozhodují o tom, jak je nadřazený objekt vytvořen a jaký typ objektů nadřazený objekt obsahuje.
Definice
"Definujte rozhraní pro vytvoření objektu, ale nechte podtřídy rozhodnout, kterou třídu vytvořit instanci. Metoda Factory umožňuje třídě odložit instanci, kterou používá k vytvoření podtříd." (Gang čtyř )
Vytvoření objektu často vyžaduje složité procesy, které není vhodné zahrnout do skládajícího se objektu. Vytvoření objektu může vést k významné duplikaci kódu, může vyžadovat informace, které nejsou přístupné skládajícímu se objektu, nemusí poskytovat dostatečnou úroveň abstrakce nebo jinak nemusí být součástí skládajícího se objektu obavy. Návrhový vzor tovární metody řeší tyto problémy definováním samostatného metoda pro vytváření objektů, které podtřídy pak lze přepsat a určit odvozený typ produktu, který bude vytvořen.
Vzor tovární metody se spoléhá na dědičnost, protože vytváření objektů je delegováno na podtřídy, které implementují tovární metodu pro vytváření objektů.[3]
Struktura
Diagram tříd UML
Ve výše uvedeném UML třídní diagram, Tvůrce
třída, která vyžaduje a Produkt
objekt nevytváří instanci Produkt1
třída přímo. Místo toho Tvůrce
odkazuje na samostatný factoryMethod ()
k vytvoření objektu produktu, který umožňuje Tvůrce
nezávisle na konkrétní instanční třídě. Podtřídy Tvůrce
může předefinovat, která třída má být vytvořena. V tomto příkladu Tvůrce
podtřída implementuje abstrakt factoryMethod ()
vytvořením instance Produkt1
třída.
Příklad
Bludiště lze hrát ve dvou režimech, jeden s běžnými místnostmi, které jsou propojeny pouze s přilehlými místnostmi, a druhý s kouzelnými místnostmi, které umožňují náhodný transport hráčů.
Struktura
Pokoj, místnost
je základní třída pro finální produkt (MagicRoom
nebo Obyčejný pokoj
). MazeGame
deklaruje abstraktní tovární metodu výroby takového základního produktu. MagicRoom
a Obyčejný pokoj
jsou podtřídy základního produktu implementujícího finální produkt. MagicMazeGame
a OrdinaryMazeGame
jsou podtřídy MazeGame
implementace tovární metody výroby finálních produktů. Tovární metody tedy oddělují volající (MazeGame
) z implementace konkrétních tříd. Díky tomu je „nový“ operátor nadbytečný a umožňuje dodržování Princip otevřeno / zavřeno a činí finální produkt flexibilnějším v případě změny.
Ukázkové implementace
C#
// Prázdná slovní zásoba skutečného objektuveřejnost rozhraní IPerson{ tětiva GetName();}veřejnost třída Vesničan : IPerson{ veřejnost tětiva GetName() { vrátit se „Vesnická osoba“; }}veřejnost třída CityPerson : IPerson{ veřejnost tětiva GetName() { vrátit se „Městská osoba“; }}veřejnost výčet PersonType{ Venkovský, Městský}/// /// Implementace Factory - Používá se k vytváření objektů./// veřejnost třída Továrna{ veřejnost IPerson GetPerson(PersonType typ) { přepínač (typ) { případ PersonType.Venkovský: vrátit se Nový Vesničan(); případ PersonType.Městský: vrátit se Nový CityPerson(); výchozí: házet Nový NotSupportedException(); } }}
Ve výše uvedeném kódu můžete vidět vytvoření jednoho volaného rozhraní IPerson
a nazvané dvě implementace Vesničan
a CityPerson
. Na základě typu předaného do Továrna
objekt, vracíme původní konkrétní objekt jako rozhraní IPerson
.
Tovární metoda je jen doplněním Továrna
třída. Vytvoří objekt třídy prostřednictvím rozhraní, ale na druhou stranu také nechá podtřídu rozhodnout, která třída je vytvořena.
veřejnost rozhraní IProdukt{ tětiva GetName(); tětiva NastavitCenu(dvojnásobek cena);}veřejnost třída Telefon : IProdukt{ soukromé dvojnásobek _cena; veřejnost tětiva GetName() { vrátit se „Apple TouchPad“; } veřejnost tětiva NastavitCenu(dvojnásobek cena) { _cena = cena; vrátit se "úspěch"; }}/ * Téměř stejné jako u Factory, jen další expozice, aby bylo možné něco udělat pomocí vytvořené metody * /veřejnost abstraktní třída ProductAbstractFactory{ chráněný abstraktní IProdukt MakeProduct(); veřejnost IProdukt GetObject() // Implementace tovární metody. { vrátit se tento.MakeProduct(); }}veřejnost třída PhoneConcreteFactory : ProductAbstractFactory{ chráněný přepsat IProdukt MakeProduct() { IProdukt produkt = Nový Telefon(); // Po získání objektu něco s objektem udělejte. produkt.NastavitCenu(20.30); vrátit se produkt; }}
Vidíte, že jsme použili MakeProduct
v betonu Díky tomu můžete snadno volat MakeProduct ()
z toho získat IProdukt
. Můžete také napsat svoji vlastní logiku po získání objektu v konkrétní tovární metodě. GetObject je abstraktní v rozhraní Factory.
Jáva
Tento Jáva příklad je podobný jednomu v knize Designové vzory.
MazeGame používá místnosti, ale klade odpovědnost za vytváření pokojů do svých podtříd, které vytvářejí konkrétní třídy. V běžném herním režimu lze použít tuto metodu šablony:
veřejnost abstraktní třída Pokoj, místnost { abstraktní prázdnota připojit(Pokoj, místnost pokoj, místnost);}veřejnost třída MagicRoom rozšiřuje Pokoj, místnost { veřejnost prázdnota připojit(Pokoj, místnost pokoj, místnost) {}}veřejnost třída Obyčejný pokoj rozšiřuje Pokoj, místnost { veřejnost prázdnota připojit(Pokoj, místnost pokoj, místnost) {}}veřejnost abstraktní třída MazeGame { soukromé finále Seznam<Pokoj, místnost> pokoje = Nový ArrayList<>(); veřejnost MazeGame() { Pokoj, místnost pokoj1 = makeRoom(); Pokoj, místnost pokoj2 = makeRoom(); pokoj1.připojit(pokoj2); pokoje.přidat(pokoj1); pokoje.přidat(pokoj2); } abstraktní chráněný Pokoj, místnost makeRoom();}
Ve výše uvedeném fragmentu je MazeGame
konstruktor je metoda šablony to dělá nějakou společnou logiku. Odkazuje na makeRoom
tovární metoda, která zapouzdřuje vytváření místností tak, aby bylo možné v podtřídě použít jiné místnosti. Chcete-li implementovat další herní režim, který má kouzelné místnosti, stačí přepsat makeRoom
metoda:
veřejnost třída MagicMazeGame rozšiřuje MazeGame { @ Přepis chráněný Pokoj, místnost makeRoom() { vrátit se Nový MagicRoom(); }}veřejnost třída OrdinaryMazeGame rozšiřuje MazeGame { @ Přepis chráněný Pokoj, místnost makeRoom() { vrátit se Nový Obyčejný pokoj(); }}MazeGame obyčejná hra = Nový OrdinaryMazeGame();MazeGame magicGame = Nový MagicMazeGame();
PHP
Další příklad v PHP následuje, tentokrát s použitím implementací rozhraní na rozdíl od podtřídy (stejného lze dosáhnout prostřednictvím podtřídy). Je důležité si uvědomit, že tovární metodu lze také definovat jako veřejnou a vyvolat ji přímo klientským kódem (na rozdíl od výše uvedeného příkladu Java).
/ * Tovární a automobilové rozhraní * /rozhraní CarFactory{ veřejnost funkce makeCar(): Auto;}rozhraní Auto{ veřejnost funkce getType(): tětiva;}/ * Konkrétní realizace továrny a automobilu * /třída SedanFactory nářadí CarFactory{ veřejnost funkce makeCar(): Auto { vrátit se Nový Sedan(); }}třída Sedan nářadí Auto{ veřejnost funkce getType(): tětiva { vrátit se 'Sedan'; }}/ * Klient * /$ továrna = Nový SedanFactory();$ auto = $ továrna->makeCar();tisk $ auto->getType();
Krajta
Stejné jako příklad Java.
z abc import ABC, abstraktní metodatřída MazeGame(ABC): def __init__(já) -> Žádný: já.pokoje = [] já._připravit_pokoje() def _připravit_pokoje(já) -> Žádný: pokoj1 = já.make_room() pokoj2 = já.make_room() pokoj1.připojit(pokoj2) já.pokoje.připojit(pokoj1) já.pokoje.připojit(pokoj2) def hrát si(já) -> Žádný: tisk(„Přehrávání pomocí“{}"'.formát(já.pokoje[0])) @abstractmethod def make_room(já): vyzdvihnout NotImplementedError(„Měli byste to implementovat!“)třída MagicMazeGame(MazeGame): def make_room(já): vrátit se MagicRoom()třída OrdinaryMazeGame(MazeGame): def make_room(já): vrátit se Obyčejný pokoj()třída Pokoj, místnost(ABC): def __init__(já) -> Žádný: já.propojené_pokoje = [] def připojit(já, pokoj, místnost) -> Žádný: já.propojené_pokoje.připojit(pokoj, místnost)třída MagicRoom(Pokoj, místnost): def __str__(já): vrátit se "Kouzelná místnost"třída Obyčejný pokoj(Pokoj, místnost): def __str__(já): vrátit se "Obyčejný pokoj"obyčejná hra = OrdinaryMazeGame()obyčejná hra.hrát si()magicGame = MagicMazeGame()magicGame.hrát si()
Použití
- v ADO.NET, IDbCommand.CreateParameter je příkladem použití tovární metody pro připojení paralelních třídních hierarchií.
- v Qt, QMainWindow :: createPopupMenu je tovární metoda deklarovaná v rámci, kterou lze přepsat kód aplikace.
- v Jáva V továrně se používá několik továren javax.xml.parsers balík. např. javax.xml.parsers.DocumentBuilderFactory nebo javax.xml.parsers.SAXParserFactory.
- V HTML5 DOM API „Rozhraní dokumentu obsahuje metodu createElement factory pro vytváření konkrétních prvků rozhraní HTMLElement.
Viz také
- Designové vzory, velmi vlivná kniha
- Návrhový vzor, přehled návrhových vzorů obecně
- Abstraktní tovární vzor, vzor často implementovaný pomocí továrních metod
- Tvůrce vzor, další kreační vzor
- Vzor metody šablony, které mohou volat tovární metody
- Joshua Bloch myšlenka a statická tovární metoda, který podle něj nemá žádný přímý ekvivalent Designové vzory.
Reference
- ^ Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). Návrhové vzory: Prvky opakovaně použitelného objektově orientovaného softwaru. Addison Wesley. str.107ff. ISBN 0-201-63361-2.CS1 maint: více jmen: seznam autorů (odkaz)
- ^ „Návrhový vzor tovární metody - problém, řešení a použitelnost“. w3sDesign.com. Citováno 2017-08-17.
- ^ Freeman, Eric; Freeman, Elisabeth; Kathy, Sierra; Bert, Bates (2004). Hendrickson, Mike; Loukides, Mike (eds.). Hlava první návrhové vzory (brožura). 1. O'REILLY. p. 162. ISBN 978-0-596-00712-6. Citováno 2012-09-12.
- ^ „Návrhový vzor tovární metody - struktura a spolupráce“. w3sDesign.com. Citováno 2017-08-12.
- Martin Fowler; Kent Beck; John Brant; William Opdyke; Don Roberts (Červen 1999). Refaktoring: Vylepšení designu stávajícího kódu. Addison-Wesley. ISBN 0-201-48567-2.
- Gamma, Erichu; Kormidlo, Richarde; Johnson, Ralph; Vlissides, John (1994). Návrhové vzory: Prvky opakovaně použitelného objektově orientovaného softwaru. Addison-Wesley. ISBN 0-201-63361-2.
- Cox, Brad J. (1986). Objektově orientované programování: evoluční přístup. Addison-Wesley. ISBN 978-0-201-10393-9.
- Cohen, Tal; Gil, Joseph (2007). „Lepší konstrukce s továrnami“ (PDF). Journal of Object Technology. Bertrand Meyer. 6 (6): 103. doi:10.5381 / jot.2007.6.6.a3. Citováno 2007-03-12.
externí odkazy
- Tovární návrhový vzor Implementace v Javě
- Tovární metoda v UML a v LePUS3 (jazyk popisu designu)
- Zvažte statické tovární metody Joshua Bloch