samedi 27 juin 2020

Abstract Factory vs multiple Factory Methods

I am writing a library to GET data from two different stock-market servers (REST) and clean the data. The API servers have different end-points and they do not return the data in in similar formats which means data-cleaning has to be performed on it.


Abstract factory method:

class StockMarketFactory(ABC):
    @abstractmethod
    def create_stock_market_requestor(self) -> AbstractMarketRequestor:
        pass

    @abstractmethod
    def create_data_cleaner(self) -> AbstractDataCleaner:
        pass

class ConcreteMarketRequestorFactory(StockMarketFactory):
    def create_stock_market_requestor(self) -> ConcreteMarketRequestorA:
        return ConcreteMarketRequestorA()

    def create_data_cleaner(self) -> ConcreteMarketCleanerA:
        return ConcreteMarketCleanerA()


class ConcreteFactory2(StockMarketFactory):
    def create_stock_market_requestor(self) -> ConcreteMarketRequestorB:
        return ConcreteMarketRequestorB()

    def create_data_cleaner(self) -> ConcreteMarketCleanerB:
        return ConcreteMarketCleanerB()


class AbstractMarketRequestor(ABC):
    @abstractmethod
    def get_historical_data(self) -> str:
        pass

class ConcreteMarketRequestorA(AbstractMarketRequestor):
    def get_historical_data(self) -> str:
        return "The result of the Market A1."


class ConcreteMarketRequestorB(AbstractMarketRequestor):
    def get_historical_data(self) -> str:
        return "The result of the Market A2."


class AbstractDataCleaner(ABC):
    @abstractmethod
    def clean_and_manipulate_data(self, *args, **kwargs) -> None:
        pass

class ConcreteMarketCleanerA(AbstractDataCleaner):
    def clean_and_manipulate_data(self, historical_data):
        print(f"Historical data is being cleaned on A")


class ConcreteMarketCleanerB(AbstractDataCleaner):
    def clean_and_manipulate_data(self, historical_data):
        print(f"Historical data is being cleaned on B")


def client_code(factory: StockMarketFactory) -> None:
    market_a = factory.create_stock_market_requestor()
    historical_data = market_a.get_historical_data()
    cleaner_a = factory.create_data_cleaner()
    cleaner_a.clean_and_manipulate_data(historical_data)


It could also be achieved using 2 different "Factory Methods":

  1. For requesting the market for data
  2. For cleaning the data

From a design perspective, the abstract factory method seems elegant. However, the factory methods would make it easier to understand. Are these my best options or are there some other design patterns that I could use?

Aucun commentaire:

Enregistrer un commentaire