Porównanie Factory Method oraz Abstract Factory

Jakiś czas temu, podczas pogłębiania wiedzy na temat wzorców projektowych, natknąłem się na dwie zbliżone do siebie metody kreacji obiektów. Próbując zrozumieć między nimi róznicę, postanowiłem zbadać temat i popełnić na ten temat arytkuł. 


Factory Method

W tym wzorcu zamiast tworzyć obiekt bezpośrednio w ciele naszych funkcji, używamy metody (fabrycznej), która jest zdefiniowana w naszej klasie bazowej. Dzięki temu podklasy decydują jaki typ zostanie stworzony.

Jak to działa?

Wyobraźmy sobie, że mamy klasę, która tworzy różne rodzaje obsługi formatów plików graficznych. Możemy mieć bazową klasę Creator, która definiuje metodę fabryczną factory_method za pomocą której będą tworzone, jakie konkretne typy instancji mają zostać utworzone.

Kod:

Na samym początku definiujemy importy:

from __future__ import annotations
from abc import ABC, abstractmethod

Następnie definiujemy klasę która będzie pełniła rolę interfejsu do procesowania obrazków:

class Image(ABC):
@abstractmethod
def open(self) -> None:
pass

@abstractmethod
def process(self) -> None:
pass

Potem zajmujemy się implamentacjami poszczególnych kodeków do obsługi zdjęć:

class Jpeg(Image):
def open(self) -> None:
print("Open jpg Image")

def process(self) -> None:
print("Process jpg Image")


class Png(Image):
def open(self) -> None:
print("Open png Image")

def process(self) -> None:
print("Process png Image")

Po czym definiujemy interfejs fabryki:

class Creator(ABC):
@abstractmethod
def factory_method(self):
pass

def some_operation(self) -> str:
product = self.factory_method()
product.open()
return product

A teraz jej implamentacje:

class JpegCreator(Creator):
def factory_method(self) -> Image:
return Jpeg()


class PngCreator(Creator):
def factory_method(self) -> Image:
return Png()

Tworzymy funkcję do obsługi naszej fabryki:

def use_factory(creator: Creator) -> None:
x = creator.some_operation()
x.process()

Poniżej przedstawiam jej użycie:

if __name__ == "__main__":
use_factory(JpegCreator())
use_factory(PngCreator())

Abstract Factory

Decyduje nie tylko jaki typ obiektu stworzyć, ale tworzy cały zestaw powiązanych obiektów, bez konieczności ich bezpośredniego łączenia. Dodatkowo łatwo dzięki temu można zmieniać zestaw obiektów, bez zmieniania większej ilości kodu.

Jak to działa?

Zasada działania jest podobna to factory method. Rózni się tylko tym że tworzy jednocześnie nie jeden, a parę obiektów.

Kod:

Jak zawsze zaczynamy od importów:

from __future__ import annotations
from abc import ABC, abstractmethod

Następnie definiujemy dwie klasy abstrakcyjne:

  • Image - służy do otwierania obrazków
  • ImageConvertService - służy do obsługi zewnętrznego oprogramowania które zajmie się ich konwersją

class Image(ABC):
@abstractmethod
def open(self) -> None:
pass


class ImageConvertService(ABC):
@abstractmethod
def convert(self) -> None:
pass

Teraz czas na implementacje poszczegółnych typów:

class Jpeg(Image):
def open(self) -> None:
print("Open jpg Image")

class JpgConvertService(ImageConvertService):
def convert(self) -> None:
print("Process jpg Image")


class Png(Image):
def open(self) -> None:
print("Open png Image")


class PngConvertService(ImageConvertService):
def convert(self) -> None:
print("Process png Image")

Następnie definiujemy naszą fabrykę:

class AbstractFactory(ABC):
@abstractmethod
def create_image_procesor(self):
pass

@abstractmethod
def create_image_convert_service(self):
pass

Po której dziedziczą nasze funkcje do obsługi oraz konwersji zdjęć:

class JpegFactory(AbstractFactory):
def create_image_procesor(self) -> Image:
return Jpeg()

def create_image_convert_service(self):
return JpgConvertService()


class PngFactory(AbstractFactory):
def create_image_procesor(self) -> Image:
return Png()

def create_image_convert_service(self):
return PngConvertService()

Tworzymy funkcję do obsługi naszej fabryki:

def use_factory(factory: AbstractFactory) -> None:
image = factory.create_image_procesor()
image.open()
converter = factory.create_image_convert_service()
converter.convert()

Poniżej przedstawiam jej użycie:

if __name__ == "__main__":
use_factory(JpegFactory())
use_factory(PngFactory())

Podsumowanie

W prostych słowach:

  • Factory Method: Służy do tworzenia pojedynczego obiektu i pozwala podklasom decydować, jaki dokładnie obiekt ma być stworzony. Jest to idealne rozwiązanie, gdy potrzebujemy elastyczności w wyborze typu obiektu.
  • Abstract Factory: Służy do tworzenia rodzin powiązanych obiektów. Dzięki temu możemy tworzyć zestawy obiektów, co ułatwia zarządzanie i zapewnia spójność. Łączy zalety factory method.

Mam nadzieję, że te przykłady pomogły w zrozumieniu różnicy między tymi dwoma wzorcami.

Kamil Mirończuk

I kiedy czegoś gorąco pragniesz, to cały wszechświat sprzyja potajemnie twojemu pragnieniu
~Paulo Coelho

Komentarze

Zostaw komentarz

Twój adres mailowy NIE zostanie opublikowany. W razie otrzymania zapytania, otrzymasz na niego odpowiedź.
Wymagane pola są oznaczone jako *