Factory method¶
Przeznaczenie
Definiuje interfejs pozwalający na tworzenie obiektów, ale odpowiedzialność za tworzenie obiektów jest delegowana do klas pochodnych
Wykorzystuje mechanizm dziedziczenia pozwala klasom pochodnym decydować, jakiej klasy obiekt zostanie utworzony
Kontekst
Klasy konkretne charakteryzują się dużą zmiennością
Problem
Chcemy tworzyć instancje konkretnych klas w warunkach zależności tylko od abstrakcyjnych interfejsów
Klasa nie może przewidzieć, jakich klas obiekty musi tworzyć
Informacja o typie tworzonego obiektu (produktu) znana jest dopiero w czasie wykonywania programu
Scenariusz¶
Chcemy napisać framework do szybkiego tworzenia aplikacji, które zarządzają dokumentami (tekstowymi, html, xml, etc.). Typy dokumentów będą definiowane przez użytkownika. Na poziomie frameworka nie znamy typu dokumentu. Klasa abstrakcyjna Application, zarządzająca dokumentami w aplikacji, definiuje interfejs tworzenia nowego dokumentu – metodę CreateDocument(). Użytkownik, definiując typ dokumentu, musi w klasie pochodnej po Application zaimplementować metodę CreateDocument() tak, aby zwracała prawidłowy typ dokumentu.

Struktura¶

Uczestnicy¶
Product – definiuje interfejs obiektów tworzonych przez metodę wytwórczą
ConcreteProduct – dziedziczy po klasie abstrakcyjnej Product
Creator
deklaruje metodę wytwórczą, która przekazuje obiekt typu Product
może implementować domyślną implementację metody wytwórczej, która przekazuje domyślny obiekt typu Product
może wywoływać metodę wytwórczą, aby utworzyć obiekt typu Product
ConcreteCreator – przedefiniowuje metodę wytwórczą, żeby przekazywała konkretny produkt
Współpraca¶
Obiekt klasy Creator deleguje do swoich klas pochodnych odpowiedzialność za takie zdefiniowanie metody wytwórczej, by przekazywała egzemplarz odpowiedniej klasy ConcreteProduct (podklasy klasy abstrakcyjnej Product).
Konsekwencje¶
Eliminuje potrzebę wstawiania specyficznych dla danej aplikacji klas w kod. Kod aplikacji odwołuje się jedynie do klasy Product, dlatego może działać z dowolnym produktem konkretnym (dowolną podklasą klasy Product).
Tworzenie obiektów wewnątrz klasy za pomocą metody wytwórczej jest bardziej elastyczne niż tworzenie ich bezpośrednio. Wzorzec Factory Method daje podklasom punkt zaczepienia do dostarczenia rozszerzonej wersji obiektu.
Promuje luźne powiązania między obiektami, ponieważ redukuje zależność kodu aplikacji od konkretnych klas.
Umożliwia łączenie równoległych hierarchii klas:
równoległe hierarchie klas powstają wtedy, gdy klasa przekazuje niektóre ze swych zobowiązań odrębnej klasie,
metoda wytwórcza pozwala zdefiniować związek między dwiema hierarchiami.

Implementacja¶
Istnieją dwa główne sposoby implementacji wzorca:
Definiowanie klasy Creator jako:
klasy abstrakcyjnej, która nie zapewnia implementacji dla deklarowanej metody wytwórczej - podklasy muszą definiować własną implementację
klasy konkretnej zapewniającej domyślną implementację metody wytwórczej
Sparametryzowane metody wytwórcze:
metoda wytwórcza ma parametr identyfikujący rodzaj tworzonego obiektu
umożliwia pojedynczej metodzie wytwórczej tworzenie wielu rodzajów produktów
class Creator
{
public:
virtual std::unique_ptr<Product> Create(const std::string& id) const
{
if (id == "MY") return std::make_unique<MyProduct>();
if (id == "YOURS") return std::make_unique<YourProduct>();
throw std::runtime_error("Unknown ID");
}
};
class MyCreator : public Creator
{
public:
std::unique_ptr<Product> Create(const std::string& id) const override
{
if (id == "OURS") return std::make_unique<OursProduct>();
return Creator::Create(id);
}
};
auto factory = std::make_unique<MyCreator>();
std::unique_ptr<Product> p1 = factory->Create("YOURS");
std::unique_ptr<Product> p2 = factory->Create("OURS");
Wzorce pokrewne¶
Abstract Factory – fabrykę abstrakcyjną często implementuje się za pomocą metod wytwórczych.
Podsumowanie¶
Umożliwia inicjowanie przez jeden obiekt procesu tworzenia innego obiektu w sytuacji, gdy nie jest znana klasa tworzonego obiektu.
Kod klienta jest nakierowany na interfejsy.
Umożliwia łączenie równoległych hierarchii klas.