I've a need to use a builder for constructing an entity (let's call it MessageWrapper
) which needs different processing before initialization, according the type of entity that was passed to the builder.
Currently I'm using one builder. Users of the Builder will be able to pass it (currently) two types of entities which conform to an "interface".
def set_entity(self, entity: IMyInterface):
self._entity = entity
return self
# IMyInterface is ABC with abstract process() method
def _process_entity_field(interface_instance: IMyInterface):
...
return interface_instance.process()
def build(self):
...
final_message_wrapper_field = self._process_entity_field()
...
Here's where my build()
method is getting a bit messy though: MessageWrapper
also requires another field processing_type: str
, which will be either "A" or "B" (but in the future, may be "C").
I'm already taking care of the processing stage by using IMyInterface.process()
, but I find myself doing this in the build()
method:
if isinstance(self._entity, AThatConformsToMyInterface):
processing_type = "A"
elif isinstance(self._entity, BThatConformsToMyInterface):
processing_type = "B"
else:
raise RuntimeError(
f"Entity of type {self._entity.__class__.__name__} is not supported"
)
Which kinda smells?
The alternative is to eschew the interface, and break out the builder to two builders that inherit from a common base:
a) MessageWrapperFromAObjBuilder - which will simply accept AThatConformsToMyInterface
and simply set processing_type
to "A".
b) MessageWrapperFromBObjBuilder - which will simply accept BThatConformsToMyInterface
and simply set processing_type
to "B".
which removes the need for the isinstance()...
check, because we know which one of the XThatConformsToMyInterface
we got.
The disadvantages of this alternative as I see them:
-
In my mind the builder pattern is there exactly for cases where you need some kind of conditional processing in the build stage. So using two builders seems kinda meh.
-
If type
CThatConformsToMyInterface
is introduced later, I'll probably have to have a designated builder for that.
So, one builder, or two builders? (it's worth emphasizing: the builder is building the same type of object at all times, it's how they get built/processed and their processing_type: str
value that depends on XThatConformsToMyInterface
.
To make things worse/more-challenging:
BThatConformsToMyInterface
is an external library class.- I don't want to introduce another method to the
IMyInterface
"interface" which hints at whatprocessing_type: str
should be.
Aucun commentaire:
Enregistrer un commentaire