Ask A Question

Notifications

You’re not receiving notifications from this thread.

Liskov Substitution Principle Discussion

Awesome.

Keep up the SOLID principles work.
Reply
Great Episode !! Looking forward to the other episodes!!
Reply
A classic symptom of LSP violation is the Refused Bequest code smell, and the opening example (with the subclass raising an exception) is a nice example.

Hard to believe you said all that about birds and types and didn't mention ducks ;)

Reply

So how to check if the bird can fly in case of module include?

Reply

This is a good question. Did you find out the answer?

Reply

I guess:
birds.select { |bird| bird.class.included_modules.include? Flying }

Reply

or like this
birds.select { |bird| bird.respond_to?(:can_fly?) }

Reply

It's not only the initial class design that led to a LSP violation, it's also the function using the classes. Both made the error to assume that all birds can fly.

Having to change the contract in that migrate_south can't use generic Birds anymore is exactly what the LSP is supposed to prevent. So, instead of treating the symptom, let's refactor the abstraction, especially the interface, correctly. The key is that all birds can travel.

def migrate_south(birds)
  birds.each do |bird|
      bird.travel(AFRICA)
    end
end

class Bird
  def travel(destination)
      walk(destination)
    end

    private

    def walk(destination)
    end
end

class Emu < Bird
end

class FlyingBird < Bird
  def travel(destination)
      fly(destination)
    end

    private

    def fly(destination)
    end
end

class Eagle < FlyingBird
end

class Penguin < Bird
  def travel(destination)
      if (walking_distance?(destination))
          walk(destination)
        else
          book_trip(destination)
        end
    end

    private

  def walking_distance?(destination)
    end

    def book_trip(destination)
    end
end

The refactoring would first introduce the travel method which simply calls fly, so altering migrate_south to use travel instead of fly won't change the app behaviour. Then we introduce the FlyingBird; thanks to the LSP we can make it the Eagle's new parent class without problems. We also make walk a Bird's default mode of travel. Finally, we can introduce the Penguin class — all without breaking migrate_south.

Reply

You'll need to throw an exception for penguins already located at the south pole.

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 82,464+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.