Blog JSystems - z miłości do programowania

Wzorzec projektowy - Fabryka Abstrakcyjna



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()

Przyjdź do nas na szkolenie z języka Python! Mamy szereg szkoleń w ofercie, od podstawowych po aplikacje webowe z użyciem Django, analizę danych, tesowanie, machine learning i wiele innych.
Sprawdź dostępne szkolenia Python
Zapisz się do newslettera aby otrzymywać najnowsze świeżynki pojawiające się na blogu!