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? Is it cleaner to implement a combination of factory and builder design pattern?
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()
```