2011-09-19 16 views
6

Według książki.fabryka metoda wzornictwo

Istotą Wzór fabryczna jest „Zdefiniować interfejs dla tworzenia obiektu, ale niech podklasy zdecydować, która klasa instancję metody fabryki pozwala na konkretyzacji klasy odraczać podklasy

Say mam klasy Autor:.

class Product; //this is what the Factory Method should return 
class Creator { 
    public: 
     Creator() //ctor 
     { //... } 

     virtual Product make(//args) 
     { //... } 
} 

Ok, to moja klasa Creator, ale nie rozumiem

Sposób Fabryka pozwala klasę odroczenia instancji do podklasy

Co to ma wspólnego z podklasy? A do czego mam używać podklas?

Ktoś może dać mi przykład?

Odpowiedz

9

Twoja klasa Creator jest fabrycznie. Nazwijmy to numerem ProductFactory, aby przykład był bardziej wyraźny.

(jestem zakładając używasz C++)

class Book : public Product 
{ 
}; 

class Computer : public Product 
{ 
}; 

class ProductFactory 
{ 
public: 
    virtual Product* Make(int type) 
    { 
    switch (type) 
    { 
     case 0: 
     return new Book(); 
     case 1: 
     return new Computer(); 
     [...] 
    } 
    } 
} 

nazwać to tak:

ProductFactory factory = ....; 
Product* p1 = factory.Make(0); // p1 is a Book* 
Product* p2 = factory.Make(1); // p2 is a Computer* 
// remember to delete p1 and p2 

Tak więc, aby odpowiedzieć na pytanie:

Co robi mieć do czynienia z podklasami? I do czego mam używać podklas ?

Co oznacza definicja fabrycznego wzorca, to że fabryka definiuje wspólny interfejs API do tworzenia wystąpień określonego typu (zwykle jest to interfejs lub klasa abstrakcyjna), ale rzeczywisty typ zwróconych implementacji (a więc podklasa odniesienie) jest obowiązkiem fabryki. W tym przykładzie fabryka zwraca instancje Product, dla których Book i Computer są poprawnymi podklasami.

Istnieją inne idiomy dla fabryki, jakby API dla fabryki i konkretnych wdrożeń fabryce nie zaakceptować type jak w moim przykładzie, ale są one w połączeniu z typem przypadkach zwracane, tak :

class ProductFactory 
{ 
public: 
    virtual Product* Make() = 0; 
} 

class BookProductFactory : public ProductFactory 
{ 
public: 
    virtual Product* Make() 
    { 
     return new Book(); 
    } 
} 

W tej klasie BookProductFactory zawsze zwraca Book instancji.

ProductFactory* factory = new BookProductFactory(); 
Product* p1 = factory->Make(); // p1 is a Book 
delete p1; 
delete factory; 

Żeby było jasne, ponieważ nie wydaje się być nieco pomylenia Abstract Factory i Factory method wzorców projektowych, zobaczmy konkretny przykład:

Korzystanie Abstract Factory

class ProductFactory { 
protected: 
    virtual Product* MakeBook() = 0; 
    virtual Product* MakeComputer() = 0; 
} 

class Store { 
public: 
    Gift* MakeGift(ProductFactory* factory) { 
    Product* p1 = factory->MakeBook(); 
    Product* p2 = factory->MakeComputer(); 
    return new Gift(p1, p2); 
    } 
} 

class StoreProductFactory : public ProductFactory { 
protected: 
    virtual Product* MakeBook() { return new Book(); } 
    virtual Product* MakeComputer() { return new Computer(); } 
} 

class FreeBooksStoreProductFactory : public StoreProductFactory { 
protected: 
    virtual Product* MakeBook() { 
    Book* b = new FreeBook(); // a FreeBook is a Book with price 0 
    return b; 
    } 
} 

Jest to używane w następujący sposób:

Store store; 
ProductFactory* factory = new FreeBooksStoreProductFactory(); 
Gift* gift = factory->MakeGift(factory); 
// gift has a FreeBook (Book with price 0) and a Computer 
delete gift; 
delete factory; 

Użycie metody fabryki

class Store { 
public: 
    Gift* MakeGift() { 
    Product* p1 = MakeBook(); 
    Product* p2 = MakeComputer(); 
    return new Gift(p1, p2); 
    } 

protected: 
    virtual Product* MakeBook() { 
    return new Book(); 
    } 

    virtual Product* MakeComputer() { 
    return new Computer(); 
    } 
} 

class FreeBooksStore : public Store { 
protected: 
    virtual Product* MakeBook() { 
    Book* b = new FreeBook(); // a FreeBook is a Book with price 0 
    return b; 
    } 
} 

który jest używany tak:

Store* store = new FreeBooksStore(); 
Gift* gift = store->MakeGift(); 
// gift has a FreeBook (Book with price 0) and a Computer 
delete gift; 
delete store; 

Podczas korzystania z type dyskryminator tak jak ja w oryginalnym przykład używamy parametized factory methods - metoda, która wie, jak tworzyć różne rodzaje obiektów. Ale może pojawić się wzór Abstract Factory lub Factory Method. Krótka sztuczka: jeśli rozszerzasz klasę fabryczną, używasz Abstract Factory. Jeśli rozszerzasz klasę o metody tworzenia, używasz metod fabrycznych.

+0

tak, w twoim kodzie, ProductFactory jest Abstract Factory, a make jest metodą Factory, prawda? – Alcott

+0

Różnica między 'Abstract Factory' i' Factory Method' będzie kwestią samą w sobie :) Krótko mówiąc, kiedy używasz dyskryminatora typu, tak jak to zrobiłem w przykładzie, używamy "sparametryzowanych metod fabrycznych" - metody, która wie, jak tworzyć różne rodzaje obiektów. Ale może pojawić się w abstrakcyjnej fabryce lub metodzie metody Factory. Krótka sztuczka: jeśli rozszerzasz klasę fabryczną, używasz 'Abstract Factory'. Jeśli rozszerzysz klasę o _factory methods_, użyjesz 'Factory Methods'. Jeśli różnica jest nadal niejasna, stanowią inne pytanie na SO. –

+0

Aby było jasne. Moja odpowiedź nie używa wzorca projektu "Factory method", lecz wzorca projektu "Abstract Factory". –

3

Fabryczny wzór oznacza jedynie, że istnieje pewna klasa lub metoda Fabryki, której zadaniem jest tworzenie obiektów dla ciebie; zamiast tworzyć je samemu. Podobnie jak samochody są budowane w fabrykach, więc nie musisz.

Nie ma to nic wspólnego z podklasami, ale autor może próbować powiedzieć, że fabryka może często zwracać pochodną implementację klasy bazowej w oparciu o parametry, ponieważ ta podklasa może wykonać to, o co prosisz w parametrach.

Na przykład WebRequest.Create ("http://www.example.com") zwróci mi HttpWebRequest, ale WebRequest.Create ("ftp://www.example.com") zwróci mi FtpWebRequest, ponieważ oba mają różne protokoły, które są implementowane przez różne klasy, ale interfejs publiczny jest taki sam, więc ta decyzja nie musi być podjęta przez konsumenta mojego API.

1

Produkt Make() utworzy właściwy typ (podklasę) produktu na podstawie określonych warunków i "odroczy" rzeczywistą instancję dla konkretnych produktów.

(kod psuedo)

public class Product 
{ 
    public static Product Make() 
    { 
     switch(day_of_week) 
     { 
      case Monday: return new Honey(1.1); 
      case Wednesday: return new Milk(3.6); 
      case Thurday: return new Meat(0.5); 
      case Friday: return new Vegetable(1.3); 
      case Saturday: return new Vegetable(2.3); // more expensive on saturday, only factory need to know 
      default: return null; // off day! 
     } 
    } 

    // returns price based on underlying product type and hidden/auto conditions (days of week) 
    public virtual void GetPrice() { return Price; } 

    // sometimes a factory can accept a product type enum 
    // From API POV, this is easier at a glance to know avaliable types. 
    pubic enum Type { Milk, Honey, Meat, Vegetable }; 

    public static Product Make(Type, Day) 
    { 
     // create the specified type for the specified day. 
    } 
} 

public class Honey : Product { Price = arg; } 
public class Milk : Product { Price = arg; } 
public class Meat : Product { Price = arg; } 
public class Vegetable : Product { Price = arg; } 

Fabryka ukrywa wymagane dane warunkowe konstruowania różnych rodzajów produktów. Po drugie, IMHO, z punktu widzenia interfejsu API, zazwyczaj łatwiej jest zobaczyć, jakie typy produktów istnieją (zwykle z wyliczenia) i łatwiej je utworzyć z jednego punktu tworzenia.

+0

to znaczy, że metoda fabryczna może wytworzyć (zwrócić) kilka produktów, ale która z nich zostanie utworzona w fabryce i zwrócona, jest określana zgodnie z pewnymi warunkami (takimi jak argumenty przekazane do metody fabryki). – Alcott

+0

@Alcott, proszę zobaczyć więcej szczegółów dodanych do mojej odpowiedzi. – Jake

0

Mogę tylko przypuszczać, że oznacza to:

class Product; //this is what the Factory Method should return 
class Box : Product; 

class Creator { 
    public: 
     Creator() //ctor 
     { //... } 

     virtual Product* make(//args) = 0; 
}; 

class BoxCreator{ 
    public: 
     BoxCreator() 
     {} 
     virtual Product* make() 
     {} 
}; 

Creator* pCreator = new BoxCreator; 
Product* pProduct = pCreator->make(); //will create a new box 

Jednak nie jest to standardowy sposób, aby utworzyć fabrykę.

+0

to, co jest na sta? – Alcott

+0

o różnych nazwach metod w zależności od typu zwracanego lub, jak wskazał Jake, określając typ obiektu. –

0

Podanie takich przykładów w pseudokodzie jest nieco mylące, wzór jest bardzo zależny od języka. Twój przykład wygląda jak w C++, ale jest niepoprawny w C++, ponieważ make zwraca wartość Product.Jest to całkowicie sprzeczne z głównym celem Factory - aby zwrócić referencję (wskaźnik w przypadku C++) do klasy bazowej. Niektóre odpowiedzi przyjmują to jako C# lub Java (jak sądzę), gdy inni jako C++.

Factory wzór opiera się na polimorfizmie. Kluczowym punktem jest zwrócenie odwołania do klasy podstawowej Product. Dzieci Factory stworzą wystąpienia konkretnych klas.

0

Mam takie samo zamieszanie "niech klasy podrzędne decydują, która klasa tworzyć" - Z uwagi na zastosowanie metody fabrykacji przy użyciu nowych do stworzenia obiektu "- Odnoszę się do pierwszej książki wzorcowej Head, w której jasno to o niej mówi w następujący sposób: "Tak jak w oficjalnej definicji usłyszysz często, że programiści mówią, że niech podklasa decyduje, którą klasę utworzyć. Mówią" decydują "nie dlatego, że wzorzec pozwala klasie podklasy decydować o uruchomieniu, ale ponieważ klasa twórców jest napisana bez wiedzy rzeczywistego produktu, który zostanie utworzony, o czym decyduje wyłącznie wybór podklasy, która jest używana "

0

Prosta i krótka:

W fabryce, to jest zaznaczone, które „podklasy” jest zobowiązany do wystąpienia tak "let the subclasses decide which class to instantiate"
(użyć instrukcji warunkowych w klasie fabryki, gdzie decyzja musi zostać wykonana.)

"define an interface or abstract class for creating an object". oczywiście, przechowujesz obiekt w odnośniku interfejsu, a klient nie jest świadomy, który obiekt konkretnej klasy jest zwracany. (Tak zdefiniowałeś interfejs do tworzenia obiektu).