jeudi 31 janvier 2019

Passing parameters to a builder with component sub-builders

What is an appropriate design for passing keyword arguments to a builder that contains component sub-builders which each use a distinct portion of the parameter set? Is it better to pass in a single keyword parameter set which is then parsed by each sub-builder? Or is it better to explicity specify which parameter sets belong to which sub-builders when calling the parent builder?

I know "better" can be subjective in these kinds of situations but I am wondering if there is some collective wisdom I can draw from, here. Also, note that in the details below I'm using a feature specific to the Python language but any thoughts on how other languages manage this situation is appreciated.

Details - I am using a builder design pattern where BuilderA contains sub-builders BuilderB() and BuilderC. My current thought on the design was to pass the same set of keyword arguments to each sub-builder:

class BuilderA():
    def __init__(self):
        self.builder_b = BuilderB()
        self.builder_c = BuilderC()

    def build(self, **build_parameters):
        artifact_b = self.builder_b.build(**build_parameters)
        artifact_c = self.builder_c.build(**build_parameters)
        # ... do something to create BuilderA's artifact ...

Each sub-builder has distinct keyword parameters:

class BuilderB():
    def build(self, param_1=None, param_2=None, **ignored_kwds):
        # ...

class BuilderC():
    def build(self, param_3=None, param_4=None, **ignored_kwds):
        # ...

Alternatively, BuilderA's API could look like this:

class BuilderA():

    def build(self, builder_b_parameters={}, builder_c_parameters={}):
        artifact_b = self.builder_b.build(**builder_b_parameters)
        artifact_c = self.builder_c.build(**builder_c_parameters)
        # ... do something to create BuilderA's artifact ...

Is one of these designs, generally, more acceptable than the other? Or is there another option I haven't considered?

Thoughts - The first design is cleaner but prevents BuilderB and BuilderC from sharing keyword names. Plus, it requires that each of their builders includes **ignored_kwds in its build method declaration. The danger of this approach is that if the user misspells a keyword argument then there can be unexpected behavior without error. On the other hand, the second design makes the interface to BuilderA more cumbersome but resolves the aforementioned issues.

Aucun commentaire:

Enregistrer un commentaire