terminal

codeando_simple

terminal

menu

terminal

search_module

guest@codeandosimple: ~/system/search $ grep -r "" .

Press [ENTER] to execute search

Status

Engine: Ready

Database: Online

Index: V2.1.0_LATEST

bash -- cat liskov-substitution.md
guest@codeandosimple: ~/blog/solid $ cat liskov-substitution.md

SOLID - LISKOV SUBSTITUTION PRINCIPLE_

// "Creativity is intelligence having fun" - Albert Einstein

The Liskov Substitution Principle (LSP) (introduced by Barbara Liskov in 1987) states that "objects of a superclass should be replaceable with objects of its subclasses without affecting the correctness of the program."

In simpler terms... if we use a class somewhere in our code, and we extend that class (inheritance), we must be able to replace it with any of the child classes, and the program should still be valid.

# Substitution and Correctness?

  • Substitution: Replacing instances of a base class with instances of subclasses.
  • Correctness: The program continues to work as expected after the substitution.

The Liskov Substitution Principle ensures that base classes are fully substitutable by their derived classes, meaning that subclasses must not change the expected behavior of the base.

# Why is it important?

Reliability

Ensures that components are interchangeable without undesirable side effects.

Reusability

Facilitates code reuse by ensuring that subclasses act as expected.

Maintainability

Code is easier to maintain as relationships between classes are clear and predictable.

# Symptoms of violation

We can identify when we are not respecting the Liskov Substitution Principle:

  • Need to check the type of a subclass before using a method.
  • Subclasses throwing exceptions in methods that the base class handles.
  • Clients of the base class cannot use subclasses without knowing the difference.

Example

Let's imagine an application that manages geometric shapes.

Without Liskov Substitution Principle

public class Rectangle {
    protected int width;
    protected int height;
    public void setWidth(int width) {
        this.width = width;
    }
    public void setHeight(int height) {
        this.height = height;
    }
    public int getArea() {
        return width * height;
    }
    }
public class Square extends Rectangle {
    public void setWidth(int width) {
        this.width = this.height = width;
    }
    public void setHeight(int height) {
        this.width = this.height = height;
    }
    }

If we use a Square instead of a Rectangle, it can cause unexpected behavior; changing the height of a Square also changes its width.

With Liskov Substitution Principle

We design the classes to ensure substitutability through a common abstraction:

public abstract class Shape {
    public abstract int getArea();
    }
public class Rectangle extends Shape {
    private int width;
    private int height;
    // setters and getters
    public int getArea() { return width * height; }
    }
public class Square extends Shape {
    private int side;
    public void setSide(int side) { this.side = side; }
    public int getArea() { return side * side; }
    }

Conclusions

By implementing the Liskov Substitution Principle, we ensure that Square and Rectangle can be used interchangeably where a Shape is expected. This eliminates the possibility of unexpected side effects due to incorrect assumptions about the behavior of subclasses.

Summary

The Liskov Substitution Principle is essential for a robust and maintainable software design. It encourages a consistent and predictable class hierarchy, which in turn facilitates extensibility and code reusability.