Pavel Patrin
Pavel Patrin

Reputation: 1736

Liskov substitution principe and promise objects

I have a base class Report:

class Report(object):
    def build():
        # ... sync report build
        return build_path  # str

And a child class that build reports in celery:

class AsyncReport(Report):
    def build():
        return task.delay(...)  # celery.result.EagerResult

Is it violates a Liskov substitution principle? I assume that yes, it violates LSP.

How to design such classes, when one logical operation (build()) has different implementations and possible different return types?

For example:

Upvotes: 3

Views: 1075

Answers (1)

bereal
bereal

Reputation: 34290

In Python inheritance technically does not play as big role as e.g. in Java due to duck-typing. However, from the design point of view you can think of some interface that both report types are expected to implement. While the concrete return type of build() may be different for the implementations, they still may (and should) be sharing some common contract they fulfill, so that the caller may use it uniformly without wondering about the types. For example:

class SyncReport(object):
    def build():
        return EagerResult(...)  # Contains build_path

class AsyncReport(object):
    def build():
        return task.delay()  # AsyncResult

EagerResult and AsyncResult are sub-classes of ResultBase, but what actually matters in Python, is that they fulfill the same contract and may be used interchangeably without knowing the exact result type. That makes SyncReport and AsyncReport interchangeable and they follow the intention of LSP (allow programming against the interface) even without a common base class.

Upvotes: 1

Related Questions