Search code examples
pythonfactoryclass-methodliskov-substitution-principle

Do factory class methods break the Liskov substitution principle?


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)

Solution

  • 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.