DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Culture and Methodologies
  3. Methodologies
  4. Finding Inner Peace With the Liskov Substitution Principle

Finding Inner Peace With the Liskov Substitution Principle

LSP says that functions that use references to base classes must be able to use objects of derived classes without knowing it. Adhering to it will spare you a headache.

Grzegorz Ziemoński user avatar by
Grzegorz Ziemoński
·
Jan. 02, 17 · Tutorial
Like (39)
Save
Tweet
Share
13.30K Views

Join the DZone community and get the full member experience.

Join For Free

We’re successfully handling divergent requirements by conforming to SRP. We’ve made our systems extensible by unleashing the power of OCP. Everything at WooMinus seems calm. But your life couldn’t be further from that. What happened?! What does this have to do with Liskov Substitution Principle? Read on to see how it will bring peace to your life.

King Benedictus and Real Politics

It’s late in the evening. Your wife asked you to go to the shop and buy a liter of milk and, if there are eggs, to get ten. So, you’re coming back carrying 10 liters of milk, the night appears so peaceful. Suddenly, a black van drives by and stops. Two big guys in hoodies punch you and force you in the car. It’s all black. A strangely familiar voice begins to whisper…

Listen carefully. I am King Benedictus. I hired a team of programmers known as the Black Dragons to write a system to control the government. Those suckers claimed it’s open for extension and similar nonsense. Yet, when I asked another team to add support for bribing different kinds of politicians, things started to break unexpectedly. I want you to find the issue and resolve it. You’ve got one hour. You fix the problem on time, and I’ll let you go and make sure you’re safe. You don’t? Pow!

Racing Against Time

You take the laptop and begin to search for the issue. The most prominent domain class in the system is Politician:

public class Politician {
    public void bribe(double dollars) {
        if(dollars < 2000)
            throw new HowDareYouException();

        changeMindAboutX();
    }

    protected void changeMindAboutX() {
        // stuff
    }
}


This must be the class that the other team tried to extend in order to add new types of politicians! You click the button to get to the subclasses and…

public class CorruptiblePolitician extends Politician {
    @Override
    public void bribe(double dollars) {
        if (dollars < 3000)
            throw new HowDareYouException();

        changeMindAboutY();
    }

    private void changeMindAboutY() {
        // stuff
    }
}


That’s weird. A corruptible politician who wants more money than a regular one? Also, he changes his mind about something completely different. This is a smell. Let’s look at Politician ‘s clients!

public class GovernmentService {
    private static final double JUST_ENOUGH_TO_FORCE_X = 2000;

    private PoliticianRepository politicianRepository;

    // stuff

    public void forceX() {
        for (Politician politician : politicianRepository.findElected()) {
            politician.bribe(JUST_ENOUGH_TO_FORCE_X);
        }
    }
}


Aha! That explains everything!

Liskov Substitution Principle

The example above is a classic violation of the Liskov Substitution Principle:

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

The person implementing GovermentService reasonably assumed that it’s enough to pay a politician 2000 dollars to make him change his mind about topic X. By adding a new type of politician to the system, the developers made the assumption invalid without fixing the broken code.

LSP and Conditions

Another way to state LSP, which I personally find much more intuitive, uses the terms usually associated with Design by Contract:

…when redefining a routine [in a derivative], you may only replace its precondition by a weaker one, and its postcondition by a stronger one.

If you look at our example from this perspective, the LSP violation should be very clear:

  • A precondition of the dollars argument being at least 2000 has been replaced by a stronger one requiring 3000.
  • A postcondition of the politician having changed his mind about X has been replaced by a weaker one of not changing mind about it.

To support this with a code example, let’s take a look at a different extension of Politician:

public class CorruptiblePolitician extends Politician {
    @Override
    public void bribe(double dollars) {
        if (dollars < 1500)
            throw new HowDareYouException();

        changeMindAboutX();
        changeMindAboutY();
    }

    private void changeMindAboutY() {
        // stuff
    }
}


This one is perfectly valid. Is it enough to pay the guy 2000? It is! Will he change his mind about X? He will! You get the point.

Restoring Your Inner Peace

Now, that you know the ins and outs of LSP, you’re ready to save your life. King Benedictus claims that the system worked before adding the new type of politician. It’s also true, that the corruptible politicians will change their mind about topic Y when paid at least 3000 dollars. Let’s make the solution take the best from the old and the new:

public class CorruptiblePolitician extends Politician {
    @Override
    public void bribe(double dollars) {
        if (dollars < 2000)
            throw new HowDareYouException();

        changeMindAboutX();

        if (dollars >= 3000)
            changeMindAboutY();
    }

    private void changeMindAboutY() {
        // stuff
    }
}


Here, the method works with the GovermentService implementation and keeps the new benefits in place. You’re safe!

One More Thing…

Before I let you go. If GovermentService didn’t exist or it used some smarter way of determining the bribe amount, the described problems wouldn’t surface and we probably would not talk about an LSP violation – we could talk about a potential one at most. This is a key characteristic of this principle – everything depends on client’s expectations.

You probably know JDK methods like Arrays.asList() and Collections.unmodifiableXxx(). If you want to be hypercorrect, these do not violate LSP, because interfaces are not types and the rule originally was about subtyping. But when you look at client’s expectations, they rarely expect a list that does not support modifying its contents. Therefore, unless it’s completely clear for everyone that the collection is not modifiable, opt for the more evident immutable collections from Guava.

Liskov substitution principle

Published at DZone with permission of Grzegorz Ziemoński, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • SAST: How Code Analysis Tools Look for Security Flaws
  • Mr. Over, the Engineer [Comic]
  • Why Open Source Is Much More Than Just a Free Tier
  • Asynchronous HTTP Requests With RxJava

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: