I'm in the process of writing an bidirectional, asynchronous socket server and server handler. The base handler class I'm working off of is as follows:
class BaseAsyncSocketHandler:
async def send(self, data: bytes) -> int
However, I want to write a subclass that sends two arguments, an event and arbitrary corresponding data, which suggests the signature:
async def send(self, event: str, data: object) -> int:
return await super().send(event_data_magic_to_bytes(event, data))
Unfortunately, this violates the Liskov substitution principle, and I don't think writing it as a mixin will makes the situation any better, so I'm hoping somebody has either seen this before or can think of a better design pattern (or tell me this is an unnecessary abstraction in the first place).
-
Does your subclass allow its users to send arbitrary bytes in addition to sending event/data combinations?Bart van Ingen Schenau– Bart van Ingen Schenau2017年04月13日 06:11:25 +00:00Commented Apr 13, 2017 at 6:11
-
No, it wouldn't. I intended for the data bytes to consist of the packaged event and serialized object. I definitely was considering optional/keyword arguments, if that's what you were suggesting though.noahbkim– noahbkim2017年04月13日 13:55:48 +00:00Commented Apr 13, 2017 at 13:55
-
Why not change the name of the method? Liskov substitution is about behavior specifications as well as signatures, but in this case, I think you are only talking about the signature.Frank Hileman– Frank Hileman2017年04月13日 22:44:28 +00:00Commented Apr 13, 2017 at 22:44
-
Ultimately, this is sort of what I did. I'll add my solution below.noahbkim– noahbkim2017年04月13日 23:13:16 +00:00Commented Apr 13, 2017 at 23:13
-
2Why are you even using inheritance? That's the real issue here!gardenhead– gardenhead2017年05月14日 03:51:07 +00:00Commented May 14, 2017 at 3:51
1 Answer 1
In the end, I settled on providing the following:
class BaseAsyncSocketHandler:
async def _send(self, data: bytes) -> int:
...
@abc.abstractmethod
async def send(self, *args, **kwargs) -> int:
pass
This way the user can implement subsets of the send method while using the base send method provided by the socket wrapper. As to why I wanted to use send
instead of just creating another class method like send_event
, I think I mostly just wanted the interface to the class to remain compact and usable while allowing for different socket methodologies.
Explore related questions
See similar questions with these tags.