Logo

dev-resources.site

for different kinds of informations.

SOLID: The Liskov Substitution Principle (LSP) in C#

Published at
12/19/2024
Categories
dotnet
designpatterns
solidprinciples
ama
Author
extinctsion
Author
11 person written this
extinctsion
open
SOLID: The Liskov Substitution Principle (LSP) in C#

Introduction

The Liskov Substitution Principle (LSP) is a foundational concept in object-oriented design, introduced by Barbara Liskov in 1987. It states:

"Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program."

In simpler terms, derived classes must be substitutable for their base classes without altering the expected behavior of the program. LSP ensures that a class hierarchy is designed in a way that promotes reusability and reliability.

Inheritance

Key Aspects of LSP

  1. Behavioral Consistency: Subclasses must adhere to the behavior defined by their base classes.
  2. No Surprises: A subclass should not override or weaken any functionality of the base class.
  3. Contracts: Subclasses should honor the "contract" (e.g., preconditions and postconditions) established by the base class.

Violating LSP often leads to fragile code that is hard to maintain or extend.

Bad code ❌

public class Rectangle
{
    public virtual double Width { get; set; }
    public virtual double Height { get; set; }

    public double GetArea() => Width * Height;
}

public class Square : Rectangle
{
    public override double Width
    {
        set { base.Width = base.Height = value; }
    }

    public override double Height
    {
        set { base.Width = base.Height = value; }
    }
}

public class LSPViolationDemo
{
    public static void Main()
    {
        Rectangle rectangle = new Square(); // Substitution occurs here
        rectangle.Width = 4;
        rectangle.Height = 5; // Expecting Width=4 and Height=5 for a rectangle

        Console.WriteLine($"Area: {rectangle.GetArea()}"); // Output: 25, not 20!
    }
}
Enter fullscreen mode Exit fullscreen mode

What's Wrong? ❌

Substituting Square for Rectangle violates expectations. A rectangle can have different widths and heights, but a square enforces equal sides. The GetArea result is incorrect in this context.

Adhering to LSP: A Better Design ✔

Inheritance

To adhere to LSP, avoid forcing subclasses into incompatible behaviors. In this case, separating Rectangle and Square into distinct hierarchies solves the issue:

public abstract class Shape
{
    public abstract double GetArea();
}

public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }

    public override double GetArea() => Width * Height;
}

public class Square : Shape
{
    public double SideLength { get; set; }

    public override double GetArea() => SideLength * SideLength;
}

public class LSPAdherenceDemo
{
    public static void Main()
    {
        Shape rectangle = new Rectangle { Width = 4, Height = 5 };
        Shape square = new Square { SideLength = 4 };

        Console.WriteLine($"Rectangle Area: {rectangle.GetArea()}");
        Console.WriteLine($"Square Area: {square.GetArea()}");
    }
}
Enter fullscreen mode Exit fullscreen mode

Why This Works?

  1. Both Rectangle and Square derive from Shape, but they operate independently, adhering to their specific behaviors.
  2. LSP is preserved because the substitution respects each class's expected behavior.

Benefits of Following LSP

  1. Improved Reusability: Subclasses work seamlessly with existing code.
  2. Ease of Testing: Code that adheres to LSP is predictable and easier to test.
  3. Enhanced Maintenance: Clear boundaries between classes make debugging and extending functionality straightforward.

Conclusion

The Liskov Substitution Principle is critical for creating robust and flexible object-oriented designs. By ensuring that subclasses can be used interchangeably with their base classes without causing unexpected behavior, you build systems that are easier to maintain and extend. When designing your class hierarchies, always ask: "Can this subclass replace its base class without altering the program's behavior?"

Following LSP not only strengthens your adherence to SOLID principles but also sets the foundation for scalable and maintainable software solutions. Happy coding!

dance

Let connect on LinkedIn and checkout my GitHub repos:

solidprinciples Article's
30 articles in total
Favicon
ISP - O Princípio da Segregação de Interface
Favicon
Disadvantages of the Single Responsibility Principle(SRP)
Favicon
Guia: O que é SOLID
Favicon
Interface Segregation Principle (ISP)
Favicon
Dependency Inversion Principle (DIP)
Favicon
Liskov Substitution Principle (LSP)
Favicon
Create your own Logger using Open-closed principle
Favicon
SOLID: Dependency Inversion Principle (DIP) in C#
Favicon
SOLID: Principio de Abierto/Cerrado
Favicon
LSP - O Princípio da Substituição de Liskov
Favicon
SOLID: Principio de Responsabilidad Única
Favicon
SOLID Principles for React / React Native Development
Favicon
Single Responsibility Principle (SRP)
Favicon
Solid Prensipleri
Favicon
Mastering SOLID Principles in .NET Core: A Path to Clean and Scalable Code
Favicon
OCP - O Princípio Aberto/Fechado
Favicon
SRP - O Princípio da Responsabilidade Única
Favicon
SOLID Design Principles
Favicon
Rethinking interfaces in Flutter projects
Favicon
Understanding the SOLID Principles in PHP and How They Improve Code Quality
Favicon
SOLID: The Liskov Substitution Principle (LSP) in C#
Favicon
Is Clean Code really practical?
Favicon
Open/Closed Principle (OCP)
Favicon
Single Responsibility Principle (SRP)
Favicon
Solid Principle in Simple English
Favicon
Why Clean Architecture and SOLID Principles Should Be the Foundation of Your Next Project!
Favicon
Seja um desenvolvedor melhor com S.O.L.I.D.
Favicon
SOLID: Open-Closed Principle (OCP) in C#
Favicon
SOLID Principles Explained in a Simple Way 🛠️✨ with Real-Life Examples
Favicon
Object Oriented Design Balance With Understanding Anti-Single Responsibility Principle

Featured ones: