Re: Struggling with liskov substitution principle (again).
| From: | Christoph Becker | Date: | Tue, 22 Jul 2014 23:08:09 +0000 |
| Subject: | Re: Struggling with liskov substitution principle (again). | ||
| References: | 1 | Groups: | php.general |
| Request: | Send a blank email to php-general+get-323646@lists.php.net to get a copy of this message | ||
Richard Quadling wrote:
> If I have a method that requires a piece of fruit. And I have a base fruit
> object that has all the properties and methods I need to operate upon it at
> the general level, why can't I extend that into a apples and oranges and
> extend the controller (appleController, orangeController) both of which are
> based upon fruitController (that layer wants fruit - be it apples, oranges
> or pears or anything that extends fruit).
In your case the Liskov Substition Principle is all about
*contravariant* parameter/argument types. There is a nice article
available at
<http://www.gnu.org/software/sather/docs-1.2/tutorial/type-conformance.html>,
which helped me to understand this issue.
They are using a very descriptive example, using omnivores, herbivores
and carnivores. At a first glance, it seems reasonable to make
herbivores and carnivores a subtype of omnivores (among others, both can
eat). Obviously, meat and plants are a subtype of food, so one can
think of:
class Food {}
class Plant extends Food {}
class Meat extends Food {}
class Omnivore {
function eat(Food $food) {}
}
class Herbivore extends Omnivore {
function eat(Plant $plant) {}
}
class Carnivore extends Omnivore {
function eat(Meat $meat) {}
}
However, that doesn't work out. Consider an animal of type Omnivore,
which is actually a cow. According to the definition of Omnivore, you
can feed it any food--but surely the cow won't eat meat! This is why
PHP emits a "strict" warning for the code above.
Actually, the problem is that this subtyping relationship is not an
*is-a* relationship (neither a herbivore nor a carnivore is an
omnivore). The same holds for your example: neither an appleController
nor an orangeController is a fruitController, because they only can deal
with apples resp. oranges, but not general fruits.
IMHO, this simple *is-a* relationship explains it all: an apple *is a*
fruit, and an orange *is a* fruit. However, an apple juicer as well as
an orange juicer *is not a* fruit juicer (at least not necessarily).
--
Christoph M. Becker