Blog JSystems - uwalniamy wiedzę!

Szukaj
Wzorzec Fabryka - jedno miejsce tworzy obiekty
Fabryka na podstawie parametru decyduje, którą klasę obiektu utworzyć

Wzorzec kreacyjny. Pozwala tworzyć rodziny obiektów dziedziczących po tej samej klasie bez określania ich konkretnych klas. Wzorzec ten powinniśmy stosować wtedy gdy zawsze chcemy użyć tego samego zestawu metod na dowolnym wybranym obiekcie z danej rodziny (klas mających wspólną klasę bazową po której dziedziczą).

Przyjmijmy że jest kilka fabryk samochodów różnych rodzajów. Jedna fabryka produkuje samochody sportowe, druga limuzyny, trzecia samochody miejskie. Wszystkie samochody, niezależnie od tego jaki jest to samochód i z jakiej fabryki pochodzi powinny posiadać metodę "jedz". Chciałbym móc tworzyć obiekt dowolnej z fabryk i odbierać obiekt dowolnego rodzaju samochodu a następnie wywoływać na obiekcie tego samochodu metodę jedz. Aby zapewnić posiadanie przez wszystkie rodzaje samochodów metody "jedz" tworzę bazową klasę abstrakcyjną ze zdefiniowaną taką metodą:

from abc import ABC,abstractmethod
class Samochod(ABC):
    @abstractmethod
    def jedz(self):
        pass

W kolejnym kroku tworzę różne klasy reprezentujące różne rodzaje samochodów. Ważne by wszystkie dziedziczyły po klasie "Samochod":

class SportowySamochod(Samochod):
    def jedz(self):
        print('sportowy wydech robi wroom!')

class Limuzyna(Samochod):
    def jedz(self):
        print('nawet nie usłyszysz dzwięku silnika...')

class SamochodMiejski(Samochod):
    def jedz(self):
        print('no niby jedzie...')

Każda z klas w inny sposób implementuje działanie metody "jedz" ale każda taką metodę posiada, co wynika z konieczności implementacji metody abstrakcyjnej klasy abstrakcyjnej po której dziedziczymy.

Przyszła pora na fabryki. Podobnie jak dowolny z samochodów ma posiadać metodę "jedz", tak każda fabryka powinna posiadać metodę "produkuj_samochod" po której oczekujemy oddania nam obiektu samochodu tworzonego przez tę właśnie fabrykę. Dla realizacji tego oczekiwania posłużymy się tę samą metodą co w przypadku klas samochodów. Utworzymy bazową klasę abstrakcyjną dla fabryk i wymusimy implementację metody "produkuj_samochod" we wszystkich dziedziczących po tej klasie klas fabryk:

class FabrykaSamochodow(ABC):
    @abstractmethod
    def produkuj_samochod(self):
        pass

Implementacja poszczególnych fabryk:

class FabrykaSportowych(FabrykaSamochodow):
    def produkuj_samochod(self):
         return SportowySamochod()

class FabrykaLimuzyn(FabrykaSamochodow):
     def produkuj_samochod(self):
         return Limuzyna()

class FabrykaMiejskich(FabrykaSamochodow):
     def produkuj_samochod(self):
         return SamochodMiejski()

Pozostaje nam już tylko kod wykonawczy który skorzysta z dobrodziejstw stworzonej przez nas struktury:

rodzaj='miejski'
if rodzaj=='sportowy':
     fabryka=FabrykaSportowych()
elif rodzaj=='limuzyna':
     fabryka=FabrykaLimuzyn()
elif rodzaj=='miejski':
     fabryka=FabrykaMiejskich()
else:
     raise NotImplementedError(f"nie ma fabryki dla typu {rodzaj}");
    samochod=fabryka.produkuj_samochod()
    samochod.jedz()

Wzależności od ustawienionej wartości w zmiennej "rodzaj" wykorzystuję obiekt właściwej dla danego rodzaju fabryki do stworzenia obiektu klasy dziedziczącej po klasie samochód. Z racji dziedziczenia wszystkich fabryk po klasie abstrakcyjnej "FabrykaSamochodow" mogę po obiekcie dowolnej fabryki spodziewać się że posiada ona metodę "produkuj_samochod". Z racji dziedziczenia wszystkich rodzajów samochodów bo abstrakcyjnej klasie "Samochod" mogę w obiekcie dowolnego samochodu spodziewać się metody "jedz". Cały kod:

from abc import ABC,abstractmethod

class Samochod(ABC):
    @abstractmethod
    def jedz(self):
        pass

class SportowySamochod(Samochod):
    def jedz(self):
        print('sportowy wydech robi wroom!')

class Limuzyna(Samochod):
    def jedz(self):
        print('nawet nie usłyszysz dzwięku silnika...')

class SamochodMiejski(Samochod):
    def jedz(self):
        print('no niby jedzie...')

class FabrykaSamochodow(ABC):
    @abstractmethod
    def produkuj_samochod(self):
        pass

class FabrykaSportowych(FabrykaSamochodow):
    def produkuj_samochod(self):
        return SportowySamochod()

class FabrykaLimuzyn(FabrykaSamochodow):
    def produkuj_samochod(self):
        return Limuzyna()

class FabrykaMiejskich(FabrykaSamochodow):
    def produkuj_samochod(self):
        return SamochodMiejski()

rodzaj='miejski'
if rodzaj=='sportowy':
    fabryka=FabrykaSportowych()
elif rodzaj=='limuzyna':
    fabryka=FabrykaLimuzyn()
elif rodzaj=='miejski':
    fabryka=FabrykaMiejskich()
else:
    raise NotImplementedError(f"nie ma fabryki dla typu {rodzaj}")
samochod=fabryka.produkuj_samochod()
samochod.jedz()
Szkolenie Python od podstaw, przez analizę danych, do machine learning w JSystems

Ten kurs daje Ci solidne podstawy Pythona. Jeśli chcesz pójść dalej i pod okiem trenera dojść od pierwszej linijki kodu do własnego modelu uczenia maszynowego, sprawdź nasze pięciodniowe szkolenie Python od podstaw, przez analizę danych, do machine learning. Pierwsze trzy dni to Python w praktyce: typy i kolekcje, instrukcje warunkowe i pętle, funkcje, moduły i pakiety, pliki tekstowe, usługi sieciowe oraz praca z bazą PostgreSQL. Czwarty dzień to analiza danych w pandas (wczytywanie CSV, TSV i XLS, filtrowanie, agregacje, statystyki) i wizualizacja w Matplotlib, Seaborn oraz Plotly. Piąty dzień to uczenie maszynowe w scikit-learn: regresja liniowa i logistyczna, drzewa decyzyjne, las losowy, XGBoost, walidacja predykcji, dobór hiperparametrów i przeciwdziałanie przeuczeniu. Szkolenie ma terminy gwarantowane, czyli odbywa się niezależnie od wielkości grupy.

Szkolenie Python od podstaw, przez analizę danych, do machine learning

To szkolenie może być dofinansowane dla Ciebie z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Najczęściej zadawane pytania

Czym jest wzorzec Fabryka Abstrakcyjna?
To wzorzec kreacyjny, który pozwala tworzyć rodziny obiektów dziedziczących po wspólnej klasie bazowej bez wskazywania ich konkretnych klas. Fabryka na podstawie parametru decyduje, którą klasę obiektu utworzyć, a kod korzystający zna tylko wspólny zestaw metod.
Kiedy warto stosować Fabrykę Abstrakcyjną?
Gdy chcemy używać tego samego zestawu metod na dowolnym obiekcie z danej rodziny klas mających wspólną klasę bazową. Dzięki temu piszemy kod działający na abstrakcji, a wybór konkretnej implementacji odkładamy do momentu wykonania, sterując nim jednym parametrem.
Jak klasa abstrakcyjna wymusza wspólne metody?
Tworzymy bazową klasę dziedziczącą po ABC i oznaczamy metodę dekoratorem abstractmethod. Wtedy każda klasa dziedzicząca musi zaimplementować tę metodę, inaczej nie da się utworzyć jej obiektu. To gwarantuje, że wszystkie samochody mają metodę jedz, a wszystkie fabryki metodę produkuj_samochod.
Jak wygląda kod wykonawczy korzystający z fabryk?
Na podstawie wartości zmiennej (na przykład rodzaj) wybieramy obiekt właściwej fabryki, a jeśli żaden typ nie pasuje, zgłaszamy wyjątek NotImplementedError. Następnie wołamy produkuj_samochod, dostajemy obiekt samochodu i wywołujemy na nim jedz, nie wnikając w jego konkretną klasę.
Jaka jest różnica między Fabryką Abstrakcyjną a Singletonem?
Oba to wzorce kreacyjne, ale rozwiązują inne problemy. Singleton pilnuje, aby istniała tylko jedna instancja klasy. Fabryka Abstrakcyjna służy do tworzenia różnych obiektów z jednej rodziny klas, ukrywając ich konkretny typ za wspólnym interfejsem.

Komentarze (0)

Musisz być zalogowany by móc dodać komentarz. Zaloguj się przez Google

Brak komentarzy...