Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class usage pitfalls breaking Liskov Substitution Principle

In a project I worked recently, noticed that some methods that were accepting a class that belongs to a hierarchy, had code similar to following:

public void Process(Animal animal) {
    if(animal.GetType() == typeof(Dog)) {
        Console.WriteLine("We have a dog");
    }
    else {
        Console.WriteLine("not a dog");
    }
}

Well, that struck me as a blatant violation of LSP, because now if you use a subclass of a dog, either in production code, unit testing mock, or as a part of dependency injection interceptor this code will not work the same way. I believe this particular scenario can be fixed easily, by changing condition to:

  if (animal is Dog)

That got me thinking though:

Are there any other pitfalls to look for that can break LSP in client code?

UPDATE

Just to clarify, I am looking for possible pitfalls in code that uses the class in a hierarchy. I am aware and I am not looking for problems with badly contstructed hierarchies - (e.g. rectangle - square problem). I am trying to find out what to look for, to make sure that the code will support dynamic mocks, interceptors, decorated classes (e.g. LoggingDog) the same way as it would handle original class.

So far after going through the answers and links I can see that the only pitfall would be to use type of the class directly - that is use GetType() method directly or through some other technology. Despite some comments here is and as operators, and even casting to base type will not break LSP in this case, as sub-classes will evaluate the same way the original class would.

like image 528
Sebastian K Avatar asked Feb 03 '13 04:02

Sebastian K


People also ask

What breaks Liskov Substitution Principle?

Asking for help, clarification, or responding to other answers. Making statements based on opinion; back them up with references or personal experience.

What is the most accurate example for Liskov Substitution Principle?

The classic example of the inheritance technique causing problems is the circle-elipse problem (a.k.a the rectangle-square problem) which is a is a violation of the Liskov substitution principle. A good example here is that of a bird and a penguin; I will call this dove-penguin problem.

Which of the following are violations of LSP?

LSP violations symptomsDerivates that override a method of the base class method to give it completely new behaviour. Derivates that override a method of the superclass by an empty method. Derivates that document that certain methods inherited from the superclass should not be called by clients.

What is LSP Liskov Substitution Principle and what are some examples of its use?

Simply put, the Liskov Substitution Principle (LSP) states that objects of a superclass should be replaceable with objects of its subclasses without breaking the application. In other words, what we want is to have the objects of our subclasses behaving the same way as the objects of our superclass.


1 Answers

If we ignore for the moment that there are indeed cases where you may need to cast to a specific type, in most cases the problem can be solved by changing the design:

public class Animal
{
    public virtual void Process()
    {
        Console.WriteLine("Animal (not a dog)");
    }
}

public class Dog : Animal
{
    public override void Process()
    {
        Console.WriteLine("We have a dog");
    }
}

By using this design, we avoid the need to cast in the code processing the animals:

var animal = ...; // maybe a Dog, maybe not
animal.Process();
like image 60
Morten Mertner Avatar answered Oct 19 '22 04:10

Morten Mertner