Exploring the Relationship Between Liskov Substitution Principle and Design Patterns
In this blog post, we explore the intriguing intersection between LSP and commonly used design patterns such as Factory Method, Strategy, and Composite.

Break the substitution contract once in a large codebase and you'll spend days tracking down the silent failures it produces. The Liskov Substitution Principle (LSP) exists precisely to prevent that. This post looks at how LSP intersects with three widely-used patterns (Factory Method, Strategy, and Composite), where each pairing reinforces the principle, and where it can quietly break it, with concrete examples to make the tricky parts tangible.
Understanding the Liskov Substitution Principle (LSP)
The principle, formalized by Barbara Liskov in 1987, is straightforward: drop a subclass in wherever the superclass is expected, and the program must still behave correctly. No special-casing. No broken contracts. Derived classes extend their base; they never undermine it.
Key Tenets of LSP:
- Behavior Preservation: Subtypes should exhibit behavior consistent with their supertypes.
- Inheritance Safety: Subclasses should extend but not contradict the behavior of the superclass.
- Client Compatibility: Clients interacting with supertype objects should work just as well with subtype objects.
LSP and Design Patterns: A Symbiotic Relationship
Factory Method Pattern
The Factory Method pattern encapsulates object creation: it defines a creation interface while letting subclasses decide which concrete type to return. That flexibility is the point. But if a subclass returns an object that cannot substitute for what the superclass produces, the whole abstraction breaks.
Example:
Consider a scenario where a Factory Method creates different types of shapes. If a subclass creates a shape that cannot be substituted for a shape created by the superclass (e.g., a shape with negative dimensions), it violates LSP.
Strategy Pattern

The Strategy pattern encapsulates algorithms into separate classes so clients can pick one at runtime. LSP is what makes that swap safe: each strategy must be substitutable for any other without changing observable behavior.
Example:
Suppose we have different payment strategies (e.g., credit card, PayPal). If each strategy implements a common interface and fulfills its contract without side effects, they adhere to LSP. Swapping one for another requires no changes to the calling code.
Composite Pattern
The Composite pattern composes objects into tree structures to represent part-whole hierarchies. LSP plays a key role in ensuring that components within the composite structure can be freely interchanged.
Example:
In a file system represented using Composite pattern, a directory and a file should both implement the same interface. If a file cannot perform operations expected from a directory (e.g., listing contents), it violates LSP.
Navigating Complexities and Ensuring LSP Adherence
- Interface Design: Define clear and consistent interfaces for classes and ensure that all subclasses adhere to these interfaces.
- Contract Compliance: Subclasses must honor the contracts established by their supertypes, maintaining preconditions and postconditions.
- Testing Strategies: Thorough testing (unit tests and integration tests alike) can surface LSP violations early in the development cycle.
Conclusion
LSP violations rarely announce themselves with a loud crash. They surface as wrong behavior in code you thought was correct. Knowing where Factory Method, Strategy, and Composite each put pressure on substitutability means you can design contracts up front rather than debug broken ones in production. Get the contracts right, and the flexibility you need in those patterns comes for free.
Working on something like this?
Get a fixed scope, timeline, and price within one business day — no obligation.


