I was wondering if factory class methods break the Liskov substitution principle.
For instance in the following Python code, does the Response.from_request
factory class method break it?
import abc
class BaseResponse(abc.ABC):
@abc.abstractmethod
def get_headers(self):
raise NotImplementedError
@abc.abstractmethod
def get_body(self):
raise NotImplementedError
class Response(BaseResponse):
def __init__(self, headers, body):
self.__headers = headers
self.__body = body
def get_headers(self):
return self.__headers
def get_body(self):
return self.__body
@classmethod
def from_request(cls, request, payload):
headers = request.get_headers()
headers["meta_data"] = payload["meta_data"]
body = payload["data"]
return cls(headers, body)
The substitution principle says that you need to be able to substitute an object with another object of a compatible type (i.e. a subtype), and it must still behave the same. You need to see this from the perspective of a function that type hints for a specific object:
def func(foo: BaseResponse):
...
This function expects an argument that behaves like BaseResponse
. What does that behave like?
get_headers()
get_body()
These are the only two methods of BaseResponse
. As long as the object you pass to func
has these two characteristics, it passes the duck test of BaseResponse
. If it further implements any additional methods, that's of no concern.
So, no, class methods don't break the LSP.