Liskov substitution principle violation

761 views Asked by At

From Wikipedia,

Liskov's notion of a behavioral subtype defines a notion of substitutability for objects; that is, if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program (e.g. correctness).

Suppose the following class hierarchy:

  1. The base abstract class - AnimalWithFur. It has a read-only property furColor that is overridden in successors.
  2. Base class's successor - Cat, which overrides furColor and returns gray.
  3. Cat's successor - Tiger, which overrides furColor and returns striped.

Then we declare a method with an argument of type Cat (not AnimalWithFur).
Is sending a Tiger instance to that method a violation of the L in SOLID?

3

There are 3 answers

9
weston On BEST ANSWER

Strictly speaking, yes. The wiki article summation of Liskov says:

"...in a program...without altering any of the desirable properties of that program"

If you go back to the original paper by Barbara Liskov, it's literally stricter in its wording, 3.3. Type Hierarchy:

If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2

(Empahsis mine)

So if you replace an instance of Cat with another instance that does something different, i.e. returning stripped not grey, then that is a Liskov violation in the original sense, because a program could be easily defined that relies on the color being grey, here:

program(Cat c){
   println(c.furColor);
}

The behaviour of that program will change if you pass it a Tiger in place of a Cat.

However, in the normal way LSP is applied, it is not a violation if you did not add extra preconditions or postconditions. This is a more practical, less academic definition as people accept that when replacing an instance of one concrete type with another you do intend to change the behaviour of the program while maintaining desirable properties of that program. So presuming the client code can handle stripped like any other colour, and grey was not required for a "desirable" property of the program then it does not violate.

0
Ross On

Short answer: not necessarily. I'd have said not with the information you've given. The key, for me, is that you don't say what the imagined new method is supposed to do.

You might consider the behaviour that you're requiring in your new method to be more important than the concern of a class hierarchy.

One way to do this is to define an interface for the behaviour your new method needs from the passed in instance / argument.

Then whichever class you might want to pass into that method can implement that interface and you break apart the concern of an inheritance hierarchy and move to being concerned with consistency of behaviour.

1
Orest Savchak On

Your question nicely describe why to use class composition instead of class inheritance. Firstly, your code is illogical - Tiger is not a Cat in your sense, Tiger is one of Cats family. From code point of view, it is bad design to override and totally replace the behavior of parent class, this is actually liskov substitution violation - your Cat class means defined cat with some concrete color, and application expects to work with it respectively, but you are overriding it with inconsistent type and change the behavior. If you would describe types hierarchy correctly, you would have abstract type Cat without furColor implemented, and types Tiger and HomeCat, but HomeCat could have different color, isn't?

If you want to have trivial example of LS violation, e.g.: You are extending List interface with custom implementation, returning size always 10, but with different count of objects inside. Each normal application expects to work with list using for statement, but will have unpredictable behavior because you've broken LS principle, and List object does not behave as it is expected.