Fabryka klas (*Factory Pattern*) ============================================== .. note:: Fabryka klas umożliwia tworzenie obiektów różnych typów w zunifokowany sposób Fabryka klas to wzorzec umożliwiający produkcję obiektów *na żądanie*, np. na podstawie napisu wczytywanego z linii poleceń lub z pliku konfiguracyjnego. Konstrukcja ta składa się co najmniej z 2 rodzajów elementów: - obiektów, które będziemy produkować (klasy dziedziczące po ``Product``) - samej fabryki - klasy, która bedzie zwracała obiekty różnych typów, które jednak dziedziczą po wspólnej klasie bazowej W klasie bazowej ``Product`` zdefiniujmy metodę ``product_feature()`` wspólną dla wszystkich klas potomnych, czyli produktów: .. literalinclude:: programy/simple_class_factory.py :language: python :linenos: :lines: 1-3 Produkty, to obiekty drukujące ustalone znaki na ekranie. Obiekty klasy ``Asterix`` drukują gwiazdki (``*``) a obiekty ``Dash`` - kreski: .. literalinclude:: programy/simple_class_factory.py :language: python :linenos: :lines: 5-19 Sama fabryka wywołuje odpowiednio konstruktory: .. literalinclude:: programy/simple_class_factory.py :language: python :linenos: :lines: 21-28 Rozwiązanie takie jest dość proste, ma jednak poważną wadę: instrukcja wielokrotnego wyboru w metodzie ``produce()`` klasy ``ProductFactory`` uniemożliwia konfigurowanie działania fabryki. Aby dodać nowy rodzaj produktu do fabryki, musimy zmodyfikować kod metody ``produce()``. Zalecanym rozwiązaniem jest wykorzystanie wzorca *Dyspozytor*. Aby poprawić fabrykę, należy dodać jeszcze jedną hierarchię klas - specjalne obiekty, które tworzą nasze produkty. W poniższym przykładzie dziedziczą one po klasie bazowej ``ObjectMaker``. W całym programie potrzebujemy zazwyczaj wiele produktów, a dla każdego z nich definiujemy odpowiedni ``ObjectMaker``. Fabryka klas natomiast jest tylko jedna. W poniższym przykładzie mamy dwa produkty: ``Dash`` oraz ``Asterix``, dla których definiujemy odpowiednio ``DashMaker`` oraz ``AsterixMaker``: .. literalinclude:: programy/class_factory.py :language: python :linenos: :lines: 21-41 Teraz fabryka klas może zarejestrować ``ObjectMaker`` dla odpowiadającego mu klucza aby powiązać z tymże kluczem wytwarzanie obiektów zadanego typu. Metoda ``produce()`` wykorzystuje teraz wzorzec *Dyspozytor*, w którego implementacji wykorzystano słownik. Konfiguracja fabryki następuje w programie głównym; należy tego dokonać jeszcze przed wyprodukowaniem jakiegokolwiek produktu. W tym celu użyjmy znaku ``*`` aby produkować gwiazdki (wiążąc go z ``AsterixMaker``) oraz ``-`` aby produkować kreski. .. literalinclude:: programy/class_factory.py :language: python :linenos: :lines: 55- Zauważ, że stworzyliśmy po jednym obiekcie każdego typu ``ObjectMaker``-a, samych produktów (gwiazdek i kresek) fabryka może wyprodukować dowolnie dużo.