A Good Example of Liskov Substitution Principle

It’s usually not easy to find good examples that explain the Liskov Substitution Principle (LSP) to developers. But really, how hard could it be? The definition is so simple:

“What is wanted here is something like the following substitution property: 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 then S is a subtype of T.”

Say what? I don’t know about you, but that kind of definition usually flies way over my head. Some people use the Rectangle versus Square example to explain the principle, which is a good one, but that doesn’t necessarily relate to things we normally do.

I like Uncle Bob’s definition a lot better:

“Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.”

Recently we’ve run across a violation to that principle in a project. We have an interface defined like so:

persistedresource

It’s a very small interface that represents resources that can be loaded in memory, and persisted afterwards in case there were changes to it.

Let’s pretend we have the following implementations of that interface:

appsettings

usersettings

The actual implementation of those methods doesn’t matter here; just assume that the real implementation loads and persists application and user settings.

Somewhere in the application we have some way to retrieve a list of instances of implementations of that interface, kind of like this:

loadall[6]

Some place else, we have a method that takes in a list of those objects, and call Persist on them:

persist

And somewhere else we may use those methods, like so:

loadsave[6]

Everything works great, until a new class is added to the system in order to handle, let’s say, some “special settings”:

specialsettings

It looks like the Load method does whatever stuff it’s supposed to do in order to handle loading these special settings. The Persist method, on the other hand, throws a NotImplementedException. As it turns out, those settings are meant to be read-only, therefore, the Persist method can’t really do anything.

The system is told to load the new class along with the other ones that implement that same interface:

loadspecial[6]

Now when we run the app everything should still work fine, until we hit the code that tries to persist all of those loaded resources, at which point we get a big and fat “NotImplementedException”.

One (horrible) way to address this would be to change the SaveAll method:

newsaveall

If the specific resource being processed is of type SpecialSettings, we skip that one. Brilliant! Well, maybe not. Let’s look back at a simplified definition of the Liskov Substitution Principle:

“An object should be substitutable by its base class (or interface).”

Looking at the SaveAll method it should be clear that “SpecialSettings” is NOT substitutable by its “IPersistedResource” interface; if we call Persist on it, the app blows up, so we need change the method to take that one problem into consideration. One could say “well, let’s change the Persist method on that class so it won’t throw an exception anymore”. Hmm, having a method on a class that when called won’t do what its name implies is just bad… really, really bad.

Write this down: anytime you see code that takes in some sort of baseclass or interface and then performs a check such as “if (someObject is SomeType)”, there’s a very good chance that that’s an LSP violation. I’ve done that, and I know so have you, let’s be honest.

Another great definition for LSP comes from this motivational poster that the folks at Los Techies put together:

liskov-lostechies

So what’s the fix?

The fix here is to tailor the interface based on what each client needs (Interface Segregation Principle, or ISP). The LoadAll method (which is one client of those classes) is really only concerned about the “Load” capability, whereas the “SaveAll” method (another client) is only concerned about the “Persist” capability. In other words, these is what those clients need:

NewSaveLoad

The SaveAll takes in something tailored to its needs, IPersistResource’s, and the same goes for LoadAll, which only cares about ILoadResource’s (in the real app, the actual instantiation of these classes happen somewhere else). This is what the granular new interfaces look like:

granularinterfaces

Yup, it’s pretty much the former “IPersistedResource” split up into two separate interfaces, tailored to their client needs. Both the UserSettings and ApplicationSettings classes can implement these two interfaces, whereas the SpecialSettings class would only implement ILoadResource; this way, it isn’t forced to implement interface members it can’t handle.

Very often people ask what’s the most appropriate number of members in an interface. In the real world example I gave here, the original interface had only 2 members; one could say that was small enough, but as it turns out, it wasn’t. The IPersistedResource interface was doing too much (both loading *and* persisting stuff) based on the clients that use its implementers. In the end, two interfaces with a single method on them fit the bill a lot better. Interfaces with single responsibility? Yup, Single Responsibility Principle (SRP); as with design patterns, sometimes SOLID principles go hand in hand together.

Also check out A Good Example of Open-Closed Principle!

Advertisements

  1. #1 by Shinil on January 5, 2011 - 11:06 am

    A great post. Thank you very much

  2. #2 by Chan on January 19, 2011 - 1:12 am

    That is really great. I am clear now. Thanks!

  3. #3 by Tab on October 18, 2011 - 1:34 pm

    This principle should always be presented as “duck typing” anyway …
    If it swims like a duck and quacks like a duck, then it’s a duck (even if it’s not)

    • #4 by claudiolassala on October 18, 2011 - 1:47 pm

      Hmm… not necessarily. Borrowing from the Los Techies’ motivational posters (http://lostechies.com/derickbailey/files/2011/03/LiskovSubtitutionPrinciple_52BB5162.jpg), “if it looks like a duck, quacks like a duck, but needs batteries, you probably have the wrong abstraction”.

      • #5 by Tab on October 18, 2011 - 2:34 pm

        Yes, but if it does not need the batteries, then it’s a duck.More concretely, is a string a number ? Yes if you consider + and * in a language like python :
        (3+4)*2 = 14
        (“Hello” + “World “)*2 = “Hello World Hello World”.

        Of course, if you want to throw in / then you are in trouble, and that’s what the poster is about

      • #6 by claudiolassala on October 18, 2011 - 2:44 pm

        Agreed! 🙂

  4. #7 by ovidio on March 9, 2012 - 12:31 am

    ovidio:desde Mexico gracias por escribirlo
    !from México thanks for write it.!

  5. #8 by Deepak on January 9, 2013 - 8:20 am

    Good example.Thanks ,But one query-> this leads to use 2 different Lists to be managed right? And add or delete function from the list will bring in more complexity of updating 2 different list at a time

    • #9 by claudiolassala on January 9, 2013 - 10:56 am

      In my case there was no need to manage two different lists; adding/removing items was something done in a single spot, and nobody was supposed to deal with those lists directly, that’s why I only passed IEnumerable around.

  6. #10 by Govindan on February 12, 2013 - 8:42 am

    Nice post!

  7. #11 by Andy on March 12, 2013 - 8:05 am

    It didn’t break Liskov, it broke Interface Segregation Principle or “Don’t make me implement it” as you later identified. Liskov is not about Interfaces, it is about a base class being substitutable by a derived class without causing unexpected behaviour.

    • #12 by claudiolassala on March 17, 2013 - 11:40 am

      I believe it broke Liskov when SaveAll needed the following:

      if (r is SpecialSettings)
      return;

      In that case, IPersistedResource wasn’t substitutable by a derived class (here, the SpecialSettings class), as calling SaveAll without checking whether we were dealing with SpecialSettings would cause the code to break.

  8. #13 by Joao Paulo Lindgren on April 3, 2013 - 11:20 am

    Excellent post! I was in trouble to understand Liskov Principle, your example open my mind!
    thx!

  9. #15 by paragmParag on August 10, 2013 - 6:05 am

    I have a different opinion over this, instead of breaking IPersistedResource interface into two I would suggest to include “bool CanPersist()” method in IPersistedResource interface.

    And code would look like –

    if (r.CanPersist())
    r.Persist();

    So, not each derived class of interface IPersistedResource are substitutable for each other.

    • #16 by claudiolassala on August 13, 2013 - 9:38 am

      Yes, it can be done like that, but I still prefer splitting the interface and getting rid of the if-block altogether. But that’s just me. 🙂 Thanks for your feedback, though.

  10. #17 by frank black on January 6, 2014 - 6:12 pm

    This is about the best example I’ve seen with a good solution

  11. #19 by GoodFellasOne on January 22, 2014 - 9:50 am

    I understand that your solution does not break LSP, but I need a little more explanation on how you would use those interfaces. Say you have

    IEnumerable resources = LoadAll();

    Now you have a list of 3 ILoadResource, fine, but what if you want to persist them (those that we are allowed to persist) ?

    A solution I see is :

    SaveAll(resources.OfType());

    But I am not sure I like it. What would you suggest instead? No matter what your solution will be, the only possibility a see is to have a not mutable list (IEnumerable) that would be a subset of the list returned by LoadAll()

    • #20 by GoodFellasOne on January 22, 2014 - 9:55 am

      Correction to my previous post : all my “Generic” uses has been discarded after I posted my message, don’t know why. Like my example of SaveAll should be read as (the smaller than and greater than symbol have been replaced with brakets 😦

      SaveAll(resources.OfType{IPersistResource}());

      • #21 by claudiolassala on February 4, 2014 - 10:18 am

        Yes, I was saving it with “save all resources of type IPersistResource”… this post has been out there for a while and I hadn’t realize I forgot to add that part (even though I always mentioned that when I did presentations talking about stuff like this). 🙂

  12. #22 by soeyannaingblog1 on February 20, 2014 - 2:56 am

    Reblogged this on Configurer Corporation ©.

  13. #23 by ptreinis on May 14, 2014 - 10:54 am

    every method in interface must contain a list of exceptions it may throw(like in Java), then LSP would work because SecialSetings.Persist() method will violate interface Persist() method pattern – it should not throw exceptions.

    • #24 by Luke on May 23, 2014 - 3:17 pm

      I see your point here. But LSP can be broken also without throwing exceptions. Even if the Persist method would do nothing it will still be LSP violation. Method should do what it is supposed to do.

  14. #25 by yetibrain on February 10, 2015 - 8:41 am

    I like that you’ve solved the problem by using the ISP, but then i noticed that you can only pass objects to SaveAll() that implement IPersistResource but your LoadAll() method returned objects of type ILoadResource. GoodFellasOne then posted that one should call LoadAll() like this: IEnumerable resources = LoadAll(); In order to pass just types IPersistResource to SaveAll() indeed SaveAll(resources.OfType{IPersistResource}()) is needed. Might be more elegant compared to a if statement on the type in a loop, but still you have to deal with the correct types. LSP deals with subtypes that can subsitute their base type, but this example uses interfaces. IPersistResource and ILoadResource do not have any inheritance relation. I like this article and solution of the problem but i don’t see any LSP here, just the ISP.

  15. #26 by Domenic on September 16, 2015 - 11:42 am

    The single responsibility principle would also suggest separating the interface.

  16. #28 by agent-10 on July 12, 2016 - 2:33 pm

    I think that problem is still here.
    What exactly happens in SaveAll(resources.OfType{IPersistResource}())?
    I suppose something like:
    if (resource is IPersistResource) {…}
    Right? Problem moved but not solved..

    • #29 by claudiolassala on August 7, 2016 - 2:34 pm

      resources.OfType{IPersistResource} yields only the objects that implement that interface.

  17. #30 by Nilesh on March 27, 2017 - 11:07 am

    I have already spent few hours on understanding LSP but I was not convinced with Rectangle cs Square but now I am clear and I can say now understund what LSP is all about. Thannks fbro

  1. Software Architecture Cheat Blog 1: Design Principles « Galib's virtual identity
  2. Design and development principles | detailfocused

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: