This has really nothing to do with MVC but I came across the issue and also found a related question in that context. Unfortunately the related question fell short of describing where the LSP violation occurs in its original example and thus did not produce a satisfactory answer.
Suppose we have an MVC (or any other) framework/library providing a couple of base classes that work together as aggregates, here View
and Model
:
class Model:
def __init__(self, data):
self.data = data
class View:
def set_model(self, model: Model):
self._model = model
def draw(self):
self._draw_data(model.data)
(incomplete code obviously, but you get the idea)
Let's say I want the views in my application to always show a title. So I'll derive all my model classes from MyModel
:
class MyModel(Model):
def __init__(self, data):
self.data
self.title = ''
So far so good, no LSPs violated yet. I'll also create a new view base class which shall require its model to be of type MyModel
so that it can draw a title.
class MyView(View):
def set_model(self, model: MyModel):
super().set_model(model)
def draw(self):
super().draw()
self._draw_title(model.title)
Now I have a covariant argument on set_model
and thus violated LSP. What would be a better way to design this? Or does Liskov not apply here? If so, why?
I could obviously check the type of model
in the draw method but in a more complex real-world example I may end up adding lots of type checking code which doesn't feel right either.
set_model
function of the framework'sView
class? That's the code that might fail due to the LSP violation.