jeudi 25 mars 2021

Factory Design Pattern in Python

Situation: I have implemented a factory design pattern in Python as below. There are different screens which have different configurations. One can register the screen in the factory and get the screen in case correct configuration is passed to respective factory class method.

Question: I am wondering if this is a clean solution as each screen class (Screen1, Screen2, ..) has a main-method which calls in a specific order the respective private class methods. Is there a better/cleaner way to handle the main methods in each class?

Highly appreciate any comments and improvements!!

Code:

import numpy as np
import pandas as pd

from abc import ABCMeta, abstractmethod 

df = pd.DataFrame({"ident": ["A1", "A2", "B3", "B4"], "other_col": np.random.randint(1, 6, 4)})


class IScreens(metaclass=ABCMeta):

    @abstractmethod
    def main(self):
        pass 
    

class Screen1(IScreens):
    
    def __init__(self, data, config):
        self.data = data
        self.batch = config["cfg1"]    
    
    def __get_letter(self):
        self.data["campaign"] = self.data[self.batch].str[:1]

        return self.data
    
    def __get_number(self):
        self.data["num"] = self.data[self.batch].str[1:]

        return self.data
    
    def __some_other_stuff(self):
        self.data["other_stuff"] = self.data["num"].astype(int) * 100 / 2

        return self.data
    
    def main(self):
        self.data = self.__get_letter()
        self.data = self.__get_number()
        self.data = self.__some_other_stuff()
        # some more processing steps follow 

        return self.data
    
    
class Screen2(IScreens):
    
    def __init__(self, data, config):
        self.data = data
        self.batch = config["cfg1"]    
    
    def __some_cool_stuff(self):
        self.data["cool_other_stuff"] = self.data[self.batch] + "_COOOOL"

        return self.data
    
    def main(self):
        self.data = self.__some_cool_stuff()
        # some more processing steps follow 
        
        return self.data
        

class ScreenFactory:

    def __init__(self):
        self._screens = {}

    def register_screen(self, screen_name, screen_class):
        self._screens[screen_name] = screen_class
    
    def get_screen(self, data, config):
        
        if "screen_indicator" not in config:
            raise AssertionError("Your config file does not include 'screen_indicator' key")
        
        screen = self._screens.get(config["screen_indicator"])
        if not screen:
            raise AssertionError("screen not implemented")
        return screen(data=data, config=config)
    

factory = ScreenFactory()

factory.register_screen(screen_name="s1", screen_class=Screen1)
config = {"screen_indicator": "s1", "cfg1": "ident"}
factory.get_screen(data=df, config=config).main()

factory.register_screen(screen_name="s2", screen_class=Screen2)
config = {"screen_indicator": "s2", "cfg1": "ident"}
factory.get_screen(data=df, config=config).main()

Aucun commentaire:

Enregistrer un commentaire