Întrebări de testare a metodei fabricii de modele. Tipare generative. Implementarea clasică a modelului Factory Method

1. Nume: Metoda fabricii

2. Sarcini:

    Sistemul trebuie să rămână extensibil prin adăugarea de noi tipuri de obiecte. Utilizarea directă a noii expresii nu este recomandabilă, deoarece poate cauza ca codul pentru crearea de obiecte cu tipuri specifice să fie împrăștiat în întreaga aplicație. Atunci operațiuni precum adăugarea de obiecte de noi tipuri în sistem sau înlocuirea obiectelor de un tip cu altul vor fi dificile (mai multe detalii în secțiunea Modele generative). Modelul Factory Method permite sistemului să rămână independent atât de procesul de generare a obiectelor, cât și de tipurile acestora.

    Se știe dinainte când să creeze un obiect, dar tipul acestuia este necunoscut.

3. Soluție:

Pentru a se asigura că sistemul rămâne independent de diferite tipuri de obiecte, modelul Factory Method folosește mecanismul polimorfismului - clasele de toate tipurile finale moștenesc dintr-o clasă de bază abstractă destinată utilizării polimorfe. Această clasă de bază definește o singură interfață prin care utilizatorul va opera obiecte de tipuri finale.

Pentru a face relativ ușor adăugarea de noi tipuri în sistem, modelul Factory Method localizează crearea de obiecte de anumite tipuri într-o clasă specială de fabrică. Metodele acestei clase, prin care sunt create obiecte ale unor clase specifice, se numesc metode din fabrică.

Interfața metodelor din fabrică este declarată într-o clasă independentă de fabrică, iar implementarea lor este determinată de subclase specifice acestei clase.

4. Diagrama de clasă UML a modelului Factory Method. Implementare clasică

Produs- produsul în sine. Proiectat pentru a defini interfața obiectelor create prin metoda fabricii;

ConcreteProduct(Computer) - produse specifice care participă la schemă și sunt responsabile pentru implementarea clasei abstracte (interfață) Produs.

Creator este creatorul, iar numele lui vorbește de la sine. Acest obiect este destinat să declare o metodă din fabrică care returnează un obiect de tip Product.

ConcreteCreator- creator specific. Aici totul este evident: implementarea specifică a creatorului este angajată în returnarea unui anumit produs. În exemplul nostru, implementarea concretă a creatorului este ComputerCreator.

Creatorul are încredere în subclasele sale pentru a implementa un produs specific adecvat. Acesta este ideea Metoda fabricii.

5. Exemplu de implementare a metodei din fabrică:

Clasa Product este destinată să definească interfața obiectelor create printr-o metodă din fabrică. Aceasta este ca o carcasă de bază pentru produse. Produsul are un pret etc.

    abstract clasă Produs

    public abstract zecimal Pretul de cumparare( obține; a stabilit;}

    public abstract zecimal Preț ( obține; a stabilit;}

    public abstract şir Descriere ( obține; a stabilit;}

Creăm o clasă moștenită din clasa Product, care va încapsula logica unui anumit produs:

    clasă Computer: Produs

    privat zecimal _pretul de cumparare;

    privat zecimal _Preț;

    privat şir _Descriere;

    public Calculator( şir _Descriere, zecimal _pretul de cumparare,

    zecimal _Preț)

    acest._description = _descriere;

    acest._purchase_price = _purchase_price;

    acest._preț = _preț;

    public trece peste şir Descriere

    obține { întoarcere _Descriere; )

    a stabilit( _descriere = valoare; )

    public trece peste zecimal Preț

    obține { întoarcere _Preț; )

    a stabilit( _preț = valoare; )

    public trece peste zecimal Pretul de cumparare

    obține { întoarcere _pretul de cumparare; )

    a stabilit( _purchase_price = valoare; )

Să descriem o clasă de creator abstractă care are o metodă din fabrică.

    abstract clasă Creator

    public abstract Product FactoryMethod( şir _Descriere,

    zecimal _pretul de cumparare, zecimal _Preț);

Creăm o anumită clasă pentru creatorul unui anumit produs (moștenit de la Creator). Această clasă definește o metodă pentru constructorul clasei Computer (dacă există mai mulți constructori, atunci fiecare constructor are propria metodă din fabrică):

    clasă ComputerCreator: Creator

    public trece peste Product FactoryMethod( şir _Descriere,

    zecimal _pretul de cumparare, zecimal _Preț)

    întoarcere nou Computer(_descriere,_pret_de_achizitie,_pret);

Cod client:

    static gol Principal( şir argumente)

    Listă ProductList = nou Listă

    Creator creatori = nou Creator;

    creatori = nou ComputerCreator();

    pentru fiecare(Creator cr în creatori)

    dacă(cr este ComputerCreator)

    productList.Add(cr.FactoryMethod("Laptop", 600, 800));

    pentru fiecare(Produs pr în lista de produse)

    Console.WriteLine("Obiect de clasă (0);\n" +

    „Descriere: (1);\n” +

    „Preț de achiziție: (2);\n” +

    „Preț de vânzare: (3);\n”,

    pr.GetType().Nume,

  1. pr.PurchasePrice,

Rezultatul programului:

6. Avantaje și dezavantaje ale acestui model:

Cel mai evident dezavantaj al metodei Factory este necesitatea de a crea un succesor Creator ori de câte ori intenționați să obțineți un nou tip de produs (adică un nou ConcreteProduct). Și acest lucru, din păcate, nu poate fi evitat. Dar o problemă similară există în multe modele generative. Avantajele includ capacitatea de a crea obiecte mai universal, fără a se concentra pe clase specifice și folosind o interfață comună.

Metoda fabricii este un model de creație. Acest model de design oferă o interfață pentru crearea instanțelor unei clase. În momentul creării, moștenitorii pot determina ce clasă să instanțieze.

Cu alte cuvinte, Fabrica delegati crearea de obiecte pentru descendenții clasei părinte. Acest lucru vă permite să nu utilizați clase specifice în codul programului, ci să manipulați obiecte abstracte la un nivel superior.

Modelul de design Factory este foarte comun. Să ne uităm la un mic exemplu în Java.

Introducere: Cerințele pentru diferite tipuri de produse software sunt în continuă creștere. Rapoartele privind execuția operațiunilor aplicației ar trebui să fie generate în diferite forme: XML, HTML, text etc. Acesta este exact cazul când este convenabil să utilizați modelul Factory.

Soluție: Clasa AbstractWriter va reprezenta o abstracție pentru scrierea într-un anumit context (fie el un document XML sau un fișier text).

Clasa abstractă publică AbstractWriter ( abstract public void write(Contextul obiectului); )

Această clasă poate avea orice număr de descendenți. Să luăm în considerare subclasele ConcreteFileWriter și ConcreteXmlWriter pentru scrierea într-un fișier text și, respectiv, într-un document DOM:

Clasa publică ConcreteFileWriter extinde AbstractWriter ( scriere public void (context obiect) ( // corpul metodei ) ) clasa publică ConcreteXmlWriter extinde AbstractWriter ( scriere public void (context obiect) ( // corpul metodei ) )

Pentru a crea obiectul de care avem nevoie, putem scrie următoarea Factory:

Import java.io.File; import org.w3c.dom.Document; clasă publică FactoryMethod ( public AbstractWriter getWriter(Object object) ( writer AbstractWriter = null; if (obiect instanceof File) ( writer = new ConcreteFileWriter(); ) else if (obiect instance of Document) ( writer = nou ConcreteXmlWriter(); ) return writer ;))

În textul programului, atunci când creați un raport, trebuie să treceți un obiect File sau un document DOM la funcția getWriter. Ca urmare a executării metodei, vom primi obiectul dorit la nivelul necesar de abstractizare.

Utilizați modelul Factory în următoarele cazuri:

  • clasa nu are informații despre ce tip de obiect ar trebui să creeze;
  • clasa trece responsabilitatea pentru crearea obiectelor descendenților săi;
  • trebuie să creați un obiect în funcție de datele primite.

Într-unul dintre articolele de design ulterioare ne vom uita la model Fabrica de abstracte.

Între timp, o să vă ascult cu plăcere întrebările, observațiile și comentariile.



Comentarii: 5

Din câte am înțeles, exemplul (mulțumiri speciale pentru exemplele din ciclul despre modele) ilustrează o fabrică parametrizată, deoarece un parametru este trecut la metoda fabrică, pe baza căreia este creată o subclasă specifică AbstractWriter. Între timp, fabrica clasică, din câte am înțeles, se comportă oarecum diferit: „o clasă este concepută astfel încât obiectele pe care le creează să fie specificate prin subclase” (E. Gamma ‘Design Patterns’). Adică trebuie să existe mai mulți moștenitori FactoryMethod pentru fiecare moștenitor AbstractWriter, iar alegerea rămâne la client ce implementare FactoryMethod să aleagă. Am inteles bine?

De fapt, exemplul nu arată deloc Metoda Factory, ci așa-numita Fabrică simplă (acesta nu este nici măcar un model de design, ci pur și simplu o tehnică utilizată pe scară largă). Danik a scris corect că clasa FactoryMethod trebuie să aibă descendenți care de fapt suprascriu metoda din fabrică. La prima vedere poate părea că nu există nicio diferență, dar diferența este uriașă. Citiți „Modele de design Head First” sau „Modele de design pentru manechini” și totul va deveni clar pentru dvs.

Gresesti. Aceasta este încă o metodă din fabrică. Citim de la Erich Gamma: „metode parametrizate din fabrică. Aceasta este o altă variație a modelului care permite metodei din fabrică să creeze diferite tipuri de produse. Metodei din fabrică i se trece un parametru care identifică tipul de obiect creat.

Toate obiectele produse printr-o metodă din fabrică au o interfață produsă comună. În exemplul documentelor, clasa Aplicație poate suporta diferite tipuri de documente. Transmiteți un parametru suplimentar metodei CreateDocument, care determină ce tip de document trebuie creat.”

Deci, înainte de a-ți exprima opinia, ar fi o idee bună să studiezi partea de covoraș

Nu am înțeles ceva, prin ce diferă asta de strategia de tipar?

Poate că și eu sunt deștept. antonin yorov Diferența dintre o fabrică și o strategie este că o strategie vă permite să determinați dinamic algoritmul dorit (adică puteți conecta subclasa de interfață dorită în timpul de execuție), în timp ce o fabrică are o metodă în algoritm care returnează un obiect .

Înainte de a citi, vă rugăm să revizuiți următoarele convenții și concepte. Acest articol este actualizat cu o oarecare frecvență, așa că dacă l-ați citit înainte, nu este un fapt că datele nu s-au schimbat.

Consultați clasa generatoare modele. Ele sunt folosite pentru a defini și menține relațiile dintre obiecte. Metodele din fabrică elimină nevoia proiectantului de a construi clase specifice aplicației în cod.

Exemplu

Să presupunem că creăm un parser XML care analizează fișierul furnizat și îl convertește într-un arbore DOM. Să numim fiecare element al acestui arbore un nod. În timp ce analizăm fișierul, ne vom confrunta cu sarcina de a genera noi noduri și vom scrie acolo ceva de genul următor cod:

Clasa Xml_Node() ( /*...*/ funcția publică parse() ( /*...*/ $ChildNode = nou Xml_Node(); /*...*/ ) /*...*/ )

Ce e rău în asta? Permiteți-mi să vă dau acest exemplu: dorim să construim o structură de obiecte, o anumită clasă, pe baza unui fișier XML, pentru a-l folosi în viitor, iar noi, conform principiului „totul a fost deja scris pentru tu”, a vrut să folosească clasa gata XML_Node.

Facem propriul nostru succesor XML_Node_Processor , iar acum vrem să influențăm procesul de analiză a fișierelor astfel încât cu o anumită etichetă să fie instanțiată o anumită clasă (Pentru eticheta de hrană - My_Food, pentru vaca - My_Big_Orange_Cow). Și atunci când implementăm ca mai sus, pentru asta va trebui complet supraîncărcați metoda parse pentru a copia și lipi codul din clasa părinte prin editarea unei singure linii de cod. De acord, asta e o prostie.

Esența modelului

Posibilă implementare în PHP

Clasa abstractă XML_Node_Abstract ( funcția abstractă createNode($tag); ) clasa Xml_Node extinde XML_Node_Abstract ( /*...*/ funcția publică createNode($tag) ( returnează nou Xml_Node(); ) /*...*/ analiza funcției publice () ( /*...*/ $ChildNode = $this -> createNode($Tag); /*..*/ ) ) clasa Xml_Node_Processor extinde Xml_Node (funcția publică createNode($tag) ( switch($tag) ( case "food": return new My_Food(); case "cow": return new My_Big_Orange_Cow(); ) return parent::createNode($tag); ) ) clasa My_Food extinde Xml_Node_Processor (); clasa My_Big_Orange_Cow extinde Xml_Node_Processor();

In cele din urma

  • Într-o implementare a metodei din fabrică nu intotdeauna aveți nevoie de o clasă de creator abstract (XML_Node_Abstract). În locul ei poate fi folosită o anumită instanță. Din acest exemplu putem elimina XML_Node_Abstract si nimic nu se va schimba
  • Rezultatul returnat prin metoda din fabrică trebuie Mereu corespund unei interfețe date (în cazul nostru, interfața clasei Xml_Node)
  • O metodă din fabrică poate fi o funcție statică și poate fi folosită pentru a instanția obiecte ale unei subclase
  • Metoda fabricii nu este necesar trebuie să returneze un obiect, poate returna și o clasă. În același timp, toți moștenitorii și părinții trebuie să returneze și clasa.

Constă de fapt din metode din fabrică

Adăugat

Întrebare

Nu am inteles. Ideea este că în metoda de analiză a moștenitorilor sunt create exemple ale acestora, și nu părintele?

De ce nu in schimb:

$ChildNode = nou Xml_Node () ;

a nu face:

$ChildNode = nou static; ?

Răspuns

noua statică nu rezolvă problema pe care ar trebui să o rezolve metoda din fabrică. Sarcina sa principală este de a elimina dependența din cod, dependența de o anumită clasă. S-ar părea că ce este în neregulă cu asta? Nimic. Exact până când trebuie să extindeți clasa, să adăugați ceva logică sau să configurați testarea unitară.

Imaginați-vă că aveți acest cod în mai multe locuri:

$nod = nou Xml_Node(); $titlu = $nod->getTitle();

Managerul de proiect vine la tine și spune că xml va veni în două formate diferite. S-ar putea să vă gândiți și:

If ($this -> isFormatOne ()) ( $node = new Xml_Node (); ) else ( $node = new Xml_Node_Extended (); ) $title = $node -> getTitle ();

Apoi vine din nou și spune că acum vor fi 3.10.500 de formate. Cu o astfel de arhitectură, va trebui să faceți modificări TOATE aparițiile unui astfel de cod de fiecare dată. Dacă utilizați o metodă din fabrică, va trebui doar să o schimbați, iar crearea unui obiect va arăta întotdeauna la fel:

$nod = $this -> createNode(); $titlu = $nod -> getTitle();

Sunt de acord că articolul este foarte haotic și nu dezvăluie toată frumusețea acestui model, dar vă pot spune că acesta este unul dintre cele mai simple și în același timp utile modele. Dacă te antrenezi, în loc să generezi fără minte un obiect, pentru a delega această operație altcuiva, problemele vor deveni mult mai puține.

Metoda fabricii este un model de design generativ care rezolvă problema creării diferitelor produse fără a specifica clase specifice de produse.

O metodă din fabrică specifică o metodă care ar trebui utilizată în loc să apeleze noul operator pentru a crea obiecte de produs. Subclasele pot suprascrie această metodă pentru a schimba tipul de produse create.

Caracteristicile modelului în Java

Complexitate:

Popularitate:

Aplicabilitate: Modelul poate fi găsit adesea în orice cod Java unde este necesară flexibilitate la crearea produselor.

Modelul este utilizat pe scară largă în bibliotecile standard Java:

  • java.net.URLStreamHandlerFactory#createURLStreamHandler(String) (Răturnează diferite obiecte singleton, în funcție de protocol)
  • javax.xml.bind.JAXBContext#createMarshaller() și alte metode similare.

Semne de utilizare a unui model: O metodă din fabrică poate fi definită prin metode de creare care returnează obiecte de produs prin tipuri sau interfețe abstracte. Acest lucru vă permite să suprascrieți tipurile de produse create în subclase.

Producerea elementelor GUI multiplatformă

În acest exemplu, produsele sunt butoane, iar creatorul este un dialog.

Diferite tipuri de dialoguri au propriile lor tipuri de elemente. Prin urmare, pentru fiecare tip de dialog, creăm propria noastră subclasă și suprascriem metoda din fabrică din ea.

Fiecare dialog specific va genera butoanele care îi corespund. În același timp, codul de dialog de bază nu se va rupe, deoarece funcționează cu produse numai prin interfața lor comună.

butoane

butoane/Button.java: Interfață de buton comun

pachet site.factory_method.example.buttons; /** * Interfață comună pentru toate produsele. */ Butonul interfeței publice ( void render(); void onClick(); )

butoane/HtmlButton.java: Clasă specifică de butoane

pachet site.factory_method.example.buttons; /** * Implementarea butoanelor HTML. */ clasa publică HtmlButton implementează Button ( public void render() ( System.out.println(" "); onClick(); ) public void onClick() ( System.out.println ("Click! Butonul spune - "Bună lume!"); ) )

butoane/WindowsButton.java: O altă clasă de butoane

pachet site.factory_method.example.buttons; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * Implementarea butoanelor sistemului de operare nativ. */ clasă publică WindowsButton implementează Button ( JPanel panel = new JPanel(); JFrame frame = new JFrame(); buton JButton; public void render() ( frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel label = new JLabel("Buna ziua) Lume!"); label.setOpaque(true); label.setBackground(new Color(235, 233, 126)); label.setFont(new Font(„Dialog”, Font.BOLD, 44)); label.setHorizontalAlignment( SwingConstants.CENTER); panel.setLayout(new FlowLayout(FlowLayout.CENTER)); frame.getContentPane().add(panel); panel.add(label); onClick(); panel.add(button); frame.setSize (320, 200); frame.setVisible(true); onClick(); ) public void onClick() (buton = new JButton(„Exit”); button.addActionListener(new ActionListener() ( public void actionPerformed(ActionEvent e) ( frame.setVisible(false); System.exit(0); ) )); ) )

fabrică

factory/Dialog.java: Dialog de bază

pachet site.metoda_fabricii.exemplu..metoda_fabricii.exemplu.butoane.Buton; /** * Clasa de bază a fabricii. Rețineți că „fabrica” este doar * un rol suplimentar pentru clasă. Are deja o anumită logică de afaceri care * necesită crearea unei varietăți de produse. */ public abstract class Dialog ( public void renderWindow() ( // ... restul codului de dialog... Button okButton = createButton(); okButton.render(); ) /** * Subclasele vor suprascrie această metodă pentru a crea * obiecte de produs specifice, diferite pentru fiecare fabrică. */ public abstract Button createButton(); )

factory/HtmlDialog.java: Clasă concretă de dialoguri

site-ul pachetului.metoda_fabricii.exemplu..metoda_fabricii.exemplu.butoane..metoda_fabricii.exemplu.butoane.HtmlButton; /** * Dialog HTML. */ clasa publică HtmlDialog extinde Dialog ( @Override public Button createButton() ( return new HtmlButton(); ) )

fabrică/WindowsDialog.java: O altă clasă de dialoguri

site-ul pachetului.metoda_fabricii.exemplu..metoda_fabricii.exemplu.butoane..metoda_fabricii.exemplu.butoane.WindowsButton; /** * Dialog despre elementele sistemului de operare. */ clasă publică WindowsDialog extinde Dialog ( @Override public Button createButton() ( returnează un nou WindowsButton(); ) )

Demo.java: Cod client

pachet site.factory_method..factory_method.example.factory..factory_method.example.factory.Html.factory_method.example.factory.WindowsDialog; /** * Clasa demonstrativă. Aici se adună totul. */ public class Demo ( dialog privat static; public static void main(String args) ( configure(); runBusinessLogic(); ) /** * Aplicația creează o fabrică specifică în funcție de configurație sau * mediu. */ static void configure () ( if (System.getProperty("os.name").equals("Windows 10")) ( dialog = new WindowsDialog(); ) else ( dialog = new HtmlDialog(); ) ) /** * Orice restul codului client interacționează cu fabrica și produsele numai * printr-o interfață comună, deci nu contează care fabrică a fost creată *. */ static void runBusinessLogic() ( dialog.renderWindow(); ) )

OutputDemo.txt: Rezultat cu fabrica HtmlDialog

Clic! Button spune - „Bună lume!”

Scopul modelului Metodei fabricii

Sistemul trebuie adesea să creeze obiecte de multe tipuri diferite. Modelul Factory Method poate fi util în rezolvarea următoarelor probleme:

  • Sistemul trebuie să rămână extensibil prin adăugarea de noi tipuri de obiecte. Utilizarea directă a noii expresii nu este recomandabilă, deoarece poate cauza ca codul pentru crearea de obiecte cu tipuri specifice să fie împrăștiat în întreaga aplicație. Atunci operațiuni precum adăugarea de noi tipuri de obiecte în sistem sau înlocuirea obiectelor de un tip cu altul vor fi dificile (pentru mai multe detalii, consultați secțiunea Generarea de modele). Modelul Factory Method permite sistemului să rămână independent atât de procesul de generare a obiectelor, cât și de tipurile acestora.
  • Se știe dinainte când să creeze un obiect, dar tipul acestuia este necunoscut.

Descrierea modelului Metodei fabricii

Pentru a se asigura că sistemul rămâne independent de diferite tipuri de obiecte, modelul Factory Method folosește mecanismul polimorfismului - clasele de toate tipurile finale moștenesc dintr-o clasă de bază abstractă destinată utilizării polimorfe. Această clasă de bază definește o singură interfață prin care utilizatorul va opera obiecte de tipuri finale.

Pentru a face relativ ușor adăugarea de noi tipuri în sistem, modelul Factory Method localizează crearea de obiecte de anumite tipuri într-o clasă specială de fabrică. Metodele acestei clase, prin care sunt create obiecte ale unor clase specifice, se numesc metode din fabrică. Există două variante ale modelului Metoda fabricii:

Constructor generic , când o metodă statică din fabrică este definită în aceeași clasă de bază polimorfă de la care moștenesc clasele derivate de toate tipurile create în sistem. Identificatorul de tip al obiectului creat trebuie să fie transmis ca parametru acestei metode.

Versiunea clasică a metodei din fabrică , când interfața metodelor din fabrică este declarată într-o clasă de fabrică independentă, iar implementarea lor este determinată de subclase specifice acestei clase.

Implementarea modelului Factory Method

Să luăm în considerare ambele opțiuni pentru implementarea modelului Factory Method folosind exemplul procesului de generare a personajelor militare pentru jocul nostru strategic. Descrierea sa detaliată poate fi găsită în secțiunea Modele generative. Pentru a simplifica codul demo, vom crea personaje militare pentru o armata abstractă, fără a ține cont de caracteristicile părților în război.

Implementarea modelului Factory Method bazat pe un constructor generic

// #include #include enumerare Warrior_ID ( Infantryman_ID=0, Archer_ID, Horseman_ID ); // Ierarhia claselor de caractere ale jocului clasa Războinic ( public: virtual void info() = 0; virtual ~Warrior() () // Metoda parametrizată din fabrică statică static Warrior* createWarrior(Warrior_ID id); ); clasa Infantryman: public Warrior ( public: void info() ( cout<< "Infantryman" << endl; } }; class Archer: public Warrior { public: void info() { cout << "Archer" << endl; } }; class Horseman: public Warrior { public: void info() { cout << "Horseman" << endl; } }; // Реализация параметризированного фабричного метода Warrior* Warrior::createWarrior(Warrior_ID id) { Warrior * p; switch (id) { case Infantryman_ID: p = new Infantryman(); break; case Archer_ID: p = new Archer(); break; case Horseman_ID: p = new Horseman(); break; default: assert(false); } return p; }; // Создание объектов при помощи параметризированного фабричного метода int main() { vectorv; v.push_back(Warrior::createWarrior(Infantryman_ID)); v.push_back(Warrior::createWarrior(Archer_ID)); v.push_back(Warrior::createWarrior(Horseman_ID)); for(int i=0; i info(); // ... )

Versiunea prezentată a modelului Factory Method este populară datorită simplității sale. În ea, metoda fabrică statică createWarrior() este definită direct în clasa de bază polimorfă Warrior. Această metodă din fabrică este parametrizată, adică pentru a crea un obiect de un anumit tip, identificatorul de tip corespunzător este transmis către createWarrior().

Din punctul de vedere al „purității” codului orientat pe obiecte, această opțiune are următoarele dezavantaje:

  • Deoarece codul pentru crearea de obiecte de toate tipurile posibile este concentrat în metoda fabricii statice a clasei Warrior, clasa Warrior de bază are cunoștințe despre toate clasele derivate din aceasta, ceea ce este atipic pentru o abordare orientată pe obiecte.
  • Utilizarea unei instrucțiuni switch ca aceasta (ca în codul pentru metoda fabricii createWarrior()) este, de asemenea, descurajată în programarea orientată pe obiecte.

Aceste dezavantaje sunt absente în implementarea clasică a modelului Factory Method.

Implementarea clasică a modelului Factory Method

// #include #include // Ierarhia claselor de caractere din joc clasa Războinic ( public: virtual void info() = 0; virtual ~Warrior() () ); clasa Infantryman: public Warrior ( public: void info() ( cout<< "Infantryman" << endl; }; }; class Archer: public Warrior { public: void info() { cout << "Archer" << endl; }; }; class Horseman: public Warrior { public: void info() { cout << "Horseman" << endl; }; }; // Фабрики объектов class Factory { public: virtual Warrior* createWarrior() = 0; virtual ~Factory() {} }; class InfantryFactory: public Factory { public: Warrior* createWarrior() { return new Infantryman; } }; class ArchersFactory: public Factory { public: Warrior* createWarrior() { return new Archer; } }; class CavalryFactory: public Factory { public: Warrior* createWarrior() { return new Horseman; } }; // Создание объектов при помощи фабрик объектов int main() { InfantryFactory* infantry_factory = new InfantryFactory; ArchersFactory* archers_factory = new ArchersFactory ; CavalryFactory* cavalry_factory = new CavalryFactory ; vectorv; v.push_back(infantry_factory->createWarrior()); v.push_back(fabrica_arcași->createWarrior()); v.push_back(cavalry_factory->createWarrior()); for(int i=0; i info(); // ... )

Versiunea clasică a modelului Factory Method folosește ideea unei fabrici polimorfe. Clasa de bază polimorfă Factory, dedicată special creării de obiecte, declară interfața metodei createWarrior() factory, iar clasele derivate o implementează.

Versiunea prezentată a modelului Factory Method este cea mai comună, dar nu singura. Sunt posibile următoarele variații:

  • Clasa Factory are o implementare implicită a metodei createWarrior() factory.
  • Metoda fabrică createWarrior() a clasei Factory este parametrizată în funcție de tipul obiectului creat (cum ar fi metoda simplă Factory prezentată mai devreme) și are o implementare implicită. În acest caz, clasele derivate din fabrică sunt necesare doar pentru a defini comportamentul non-standard al createWarrior() .

Rezultatele aplicării modelului Factory Method

Avantajele modelului Factory Method

  • Creează obiecte de diferite tipuri, permițând sistemului să rămână independent atât de procesul de creare în sine, cât și de tipurile de obiecte create.

Dezavantajele modelului Metoda fabricii

  • În cazul versiunii clasice a modelului, chiar și pentru a genera un singur obiect, este necesar să se creeze o fabrică corespunzătoare