Given the following structure where I want a method with a common name for each class, but each derived class needs an additional piece of information in order to form the appropriate result. Descending the inheritance tree accumulates additional needed arguments, but always needs all parents arguments as well.
class A: @classmethod def foo(cls, a): return a class B(A): @classmethod def foo(cls, a, b): return '.'.join([super().foo(), b]) class C(B): @classmethod def foo(cls, a, b, c): return '.'.join([super().foo(), c])
>>A.foo('a') 'a' >>B.foo('a','b') 'a.b' >>C.foo('a','b','c') 'a.b.c'
Is this a frowned upon structure since the LSP does not hold? Is there a different overall design approach that would allow a common function name to account for additional arguments like this in some way?
In this example I am using class methods, but same question could be asked for normal instance methods as well.
In my case I have a messaging application with some message classes defined in an inheritance hierarchy. Each message type has a specific topic address that needs zero or more runtime parameters such as the node or workflow name. In addition each message has its own set of instance data field attributes.
class BaseMessage: sending_process: str @classmethod def topic(cls): return 'message' class WorkflowMessage(BaseMessage): @classmethod def topic(cls, node, workflow_name): return '.'.join([super().topic(), 'workflow', node, workflow_name]) @dataclass class WorkerServiceMessage(WorkflowMessage): dataA: str dataB: str @classmethod def topic(cls, node, workflow_name, worker_name): return '.'.join([super(node, workflow_name).topic(), worker_name])
class Worker: def __init__(node, workflow, name): self._node = node self._workflow = workflow self._name = name self.messenger = Messenger() self.messager.listen(topic=WorkflowMessage.topic(self._node, self._workflow), callback=self._on_msg) def _on_msg(self, msg): self.messenger.publish(topic=WorkerServiceMessage.topic(self._node, self._workflow, self._name), msg=WorkerServiceMessage(dataA='abc', dataB='123') worker=Worker('mynode', 'workflowA', 'worker1') worker.messenger.run()