SYS ARCHITECTLearning Platform
Settings
Theory

SOLID: DIP vs LSP

📋 Overview

In the SOLID design principles, the Dependency Inversion Principle (DIP) and the Liskov Substitution Principle (LSP) are often confused as they both involve abstractions. However, they address different architectural concerns: DIP focuses on the direction of dependencies to reduce coupling, while LSP focuses on behavioral correctness within inheritance hierarchies.


🏗️ Core Principles & Characteristics

  • Dependency Inversion Principle (DIP):
    1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
    2. Abstractions should not depend on details. Details should depend on abstractions.
  • Liskov Substitution Principle (LSP):
    • Subtypes must be substitutable for their base types without altering the correctness of the program.
    • It ensures that a derived class does not break the "contract" established by the parent class.

⚖️ Trade-offs: Pros & Cons

  • Pros:
    • DIP: Enables modularity, easier testing (mocking), and flexible implementation swaps.
    • LSP: Ensures robust polymorphism and prevents "fragile base class" issues.
  • Cons:
    • Over-abstraction: Applying DIP everywhere can lead to excessive interfaces and "boilerplate" code.
    • Inheritance Constraints: LSP can make inheritance hierarchies rigid, sometimes forcing developers to favor composition over inheritance.

🌍 Real-World Implementation

  • Spring/Guice (DIP): Dependency Injection containers are the ultimate realization of DIP, where services depend on interfaces and implementations are injected at runtime.
  • Java Collections (LSP): The List interface. Whether you use ArrayList or LinkedList, the code interacting with List should behave correctly (though performance characteristics may vary).
  • Plug-in Architectures: System kernels (high-level) interact with drivers (low-level) through standardized interfaces (abstractions).

💡 Interview "Gotchas" & Tips

  • The Square/Rectangle Problem: A classic LSP violation. A Square is a Rectangle mathematically, but if setHeight also changes width, it breaks the Rectangle's behavioral contract.
  • DIP != Dependency Injection: DI is a technique to achieve DIP. DIP is the principle of depending on abstractions.
  • Interface Pollution: Don't create an interface for every single class. Use DIP when you expect multiple implementations or need to decouple layers.
  • "Fail Fast" and LSP: If a subclass throws an UnsupportedOperationException for a method defined in the parent, it's a major LSP red flag.

📐 Suggested Architecture Primitives

  • Interfaces / Protocols: To define contracts (DIP/LSP).
  • Dependency Injection Containers: To manage object lifecycles and wiring.
  • Abstract Factory Pattern: To create families of related objects without specifying concrete classes.
Canvas