mardi 6 septembre 2022

Combine method implementations from different classes based on a configuration at run time

I am trying to implement a class that can dispatch the appropriate functionality based off of a configuration given. The design right now looks like this:

class TaskDoer:
    def __init__(self):
        self.task_driver = TaskDriverA()

    def do_tasks(self):
        self.task_driver.do_task1()
        self.task_driver.do_task2()
        ...


class TaskDriverA:
    def __init__(self):
        ...
    
    def do_task1(self):
        ...
    
    def do_task2(self):
        ...
    
    ...

Now I want to implement a new way to do some of the tasks based off of a configuration provided. The new ways to do tasks all fit into the same class called TaskDriverB. The tasks need to be done with a combination of TaskDriverA's methods and TaksDriverB's methods. I could implement the logic to chose the different methods in the TaskDoer like this:

class Configuration:
    def __init__(self, way_to_do_task_1_3_5, way_to_do_task_2):
        self.way_to_do_task_1_3_5 = way_to_do_task_1_3_5
        self.way_to_do_task_2 = way_to_do_task_2
        ...


class TaskDoer:
    def __init__(self, configuration):
        self.configuration = configuration
        self.task_driver_a = TaskDriverA(configuration)
        self.task_driver_b = TaskDriverB(configuration)

    def do_tasks(self):
        if (self.configuration.way_to_do_task_1_3_5 == "A")
            self.task_driver_a.do_task1()
        if self.configuration.way_to_do_task_2 == "A":
            self.task_driver_a.do_task2()
        elif self.configuration.way_to_do_task_2 == "B":
            self.task_driver_b.do_task2()
        ...

class TaskDriverA:
    def __init__(self):
        ...
    
    def do_task1(self):
        ...
    
    def do_task2(self):
        ...
    
    ...

class TaskDriverB:
    def __init__(self):
        ...
    
    def do_task1(self):
        ...
    
    def do_task2(self):
        ...

The problem here is that there are many different TaskDoers across the code base and I want to be able to dispatch the tasks more generally. My initial approach to do this was to create a task dispatcher that dispatched the correct task driver method based off the configuration. Like this:

class Configuration:
    def __init__(self, way_to_do_task_1_3_5, way_to_do_task_2):
        self.way_to_do_task_1_3_5 = way_to_do_task_1_3_5
        self.way_to_do_task_2 = way_to_do_task_2
        ...


class TaskDoer:
    def __init__(self, configurations):
        self.task_dispatcher = TaskDispatcher(configuration)

    def do_tasks(self):
        self.task_dispatcher.do_task1()
        self.task_dispatcher.do_task2()
        ...

class TaskDriverA:
    def __init__(self):
        ...
    
    def do_task1(self):
        ...
    
    def do_task2(self):
        ...
    
    ...

class TaskDriverB:
    def __init__(self):
        ...
    
    def do_task1(self):
        ...
    
    def do_task2(self):
        ...
    

class TaskDispatcher:
    def __init__(self, configuration):
        self.configuration = configuration
        self.task_driver_a = TaskDriverA()
        self.task_driver_b = TaskDriverB()
    
    def do_task1():
        if self.configuration.way_to_do_task_1_3_5 == "A":
            self.task_driver_a.do_task1()

    def do_task2():
        if self.configuration.way_to_do_task_2 == "A":
            self.task_driver_a.do_task2()
        elif self.configuration.way_to_do_task_2 == "B":
            self.task_driver_b.do_task2()
            
    ...

The problem I found with this approach is that TaskDriverA had a lot of methods while currently TaskDriverB only had a few. So writing the TaskDispatcher felt like just calling TaskDriverAs methods.

class TaskDispatcher:

    ...

    def do_task32():
        self.task_driver_a.do_task32()

    def do_task33():
        self.task_driver_a.do_task33()

    def do_task34():
        self.task_driver_a.do_task34()

    def do_task35():
        self.task_driver_a.do_task35()

    ...

Although this would work it felt wrong and I thought there must be another way. There will likely be more methods added to TaskDriverB in the future, although I do not think it would ever match A. I would appreciate it if someone could tell me a good pattern that accounts for this design.

Thank you very much

Aucun commentaire:

Enregistrer un commentaire