vendredi 7 août 2020

Python design question: When dependencies can't be instantiated ahead of time

Sorry for the poor title but if I knew the class of problems I was tackling perhaps I could find an answer.

In an ideal situation, one creates an object with all its needed dependencies, and then uses the object. However in some cases, the information needed to create a dependency is not known before the object is used.

I will try to create a concrete example that has to do with making a house. The following will be the dependencies

class WallMakerAlgorithm(abc.ABC):
    def build(self):
        # Put specific algorithm here that will build the wall
        pass

class DoorMakerAlgorithm(abc.ABC):
    def __init__(self, color: float, material: str):
        # subclasses can override init to add more fancy stuff
        self.color = color
        self.material = material

    def build(self):
        # Put specific algorithm here that will build the door
        pass

These are used by a house builder class. In the ideal case, a HouseBuilder will know its dependencies on init:

class BasicHouseBuilder:
    def __init__(self, door_maker_algorithm: DoorMakerAlgorithm, wall_maker_algorithm: WallMakerAlgorithm):
        self.door_maker_algorithm = door_maker_algorithm
        self.wall_maker_algorithm = wall_maker_algorithm

    def build(self):
        self.wall_maker_algorithm.build()
        self.door_maker_algorithm.build()

But now assume that for some (contrived) reason, the customer hasn't decided on the color of the doors. They tell you that once the wall is built, they will know the color because they will be able to see it. This creates a chicken and egg kind of problem. I can't create the HouseBuilder because I can't create the door making algorithm, and I can't create the door making algorithm without actually running HouseBuilder. Something like this:

class DecideColorLaterHouseBuilder:
   def __self__(self, wall_maker_algorithm: WallMakerAlgorithm, query_color: Callbale, ???):
      self.wall_maker_algorithm = wall_maker_algorithm
      self.query_color = query_color
      ???

   def build(self):
      self.wall_maker_algorithm.build()
      desired_door_color = self.query_color()
      # Now I want to build the door. But I don't have the door algorithm because I don't know the color!

Is there some design pattern that deals with this kind of problem? Are my abstractions just messed up in general? I can potentially add color as an argument to build of the DoorMakingAlgorithm but that just messes up my abstractions.

Aucun commentaire:

Enregistrer un commentaire