How do SOLID principles apply in LLD design?
Fast recall
Quick revision
Core answer
Ability to apply SOLID principles in practical design scenarios, not just recite textbook definitions.
Listing SOLID acronym definitions without showing how they influence actual design decisions in the given problem.
Walk through your design and explicitly call out where you applied each principle with concrete examples from your class structure.
Interview-ready guide
Interview answer
SOLID is five principles that keep object-oriented designs maintainable, and their value appears in the structure of the design rather than in memorized definitions. Single Responsibility says each class has one reason to change, which is why I split a God class into a ParkingSpot that tracks occupancy and a FeeCalculator that handles pricing. Open/Closed says code should be open to extension but closed to modification, so I add a new pricing rule as a new class rather than editing the existing lot. Liskov Substitution says a subclass must be usable anywhere its parent is, without surprises — the classic violation is a subclass that throws on a method it inherited, which breaks any code relying on the parent's contract.
Interface Segregation says prefer small, focused interfaces over one fat one, so I'd define a Payable interface rather than forcing every vehicle to implement a giant IVehicle with methods it doesn't need. And Dependency Inversion says depend on abstractions, not concrete classes, so my ParkingLot takes a FeeCalculator interface in its constructor instead of newing up a specific calculator inside itself.
The principles reinforce each other. Open/Closed and Dependency Inversion together support programming to a stable interface and adding Strategy implementations: the client depends on an abstraction, and new behaviour arrives without modifying that client. SOLID therefore explains structural decisions rather than acting as a checklist.
For example, when weekend pricing is introduced, ExitService does not gain another if branch. It receives a new WeekendFeePolicy through the existing FeePolicy interface, so the use case stays unchanged and can be tested with a fake policy.
How do SOLID principles apply in LLD design
Direct Answer
SOLID principles guide LLD design: Single Responsibility Principle means each class has one clear purpose (ParkingSpot manages occupancy, not billing). Open/Closed means you extend behavior through subclasses or interfaces, not by modifying existing code. Liskov Substitution means subclasses can replace parent classes without breaking functionality. Interface Segregation means using focused interfaces instead of one fat interface. Dependency Inversion means depending on abstractions like interfaces, not concrete classes.
Deep Dive & Architecture
SRP and OCP shape the responsibilities
ParkingSpot manages occupancy while FeeCalculator owns pricing. That is Single Responsibility. Pricing is Open/Closed when a weekend or electric-vehicle rule is added as another FeePolicy implementation rather than another branch inside the exit service.
LSP and ISP protect contracts
Liskov Substitution means every implementation must honour the promises of its interface. If ElectricSpot extends ParkingSpot but throws from a normal park() call, the hierarchy is misleading. Interface Segregation avoids that problem by using focused capabilities such as Parkable and Chargeable instead of one large spot interface.
DIP keeps orchestration testable
An ExitService can receive FeePolicy and PaymentGateway abstractions through its constructor. A test then supplies small fakes, while production supplies real implementations. SOLID is useful when each principle explains a concrete design decision; it is not a reason to add interfaces that have no alternative behaviour or testing value.
Code Example
// DIP: high-level ParkingLot depends on the FeeCalculator abstraction, not a concrete class
interface FeeCalculator { BigDecimal calculate(ParkingTicket t); }
class ParkingLot {
private final FeeCalculator fee; // abstraction
ParkingLot(FeeCalculator fee) { this.fee = fee; } // injected
}
// OCP: add weekend pricing without editing ParkingLot
class WeekendFeeCalculator implements FeeCalculator {
public BigDecimal calculate(ParkingTicket t) { /* new rule */ return BigDecimal.TEN; }
}
New pricing = new class (Open/Closed); the lot depends on the interface (Dependency Inversion).
Common Mistakes & Pitfalls
- Reciting SOLID as definitions — show it in the design (split a class, inject an interface).
- LSP violations — a subclass that throws on an inherited method breaks substitutability.
- Fat interfaces — forcing implementers to stub methods they don't need (ISP).
- Depending on concretes —
new MySqlRepo()inside a service couples them; inject the interface (DIP).
Check your understanding
Answer these without looking back at the article.
- What is Low-Level Design (LLD) and why does it exist? It translates high-level architecture into concrete class structures, relationships, and APIs that a developer can directly implement, bridging the gap between architecture and code.
- What is Low-Level Design (LLD) and what does an LLD interview expect you to do?
- What is the step-by-step process for solving an LLD interview question?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.