SOLID Principle
SOLID Principle
The Five Principles of Object-Oriented Design
1. Overview of SOLID, the Five Core Principles of Object-Oriented Design for Software Resilient to Change
flowchart LR
A["Highly coupled design<br/>vulnerable to change<br/>spaghetti code"] --"Applying the<br/>5 SOLID principles"--> B["Separation of responsibilities,<br/>extensibility, substitutable structure"] --"Improved<br/>maintainability & reusability"--> C["Software architecture<br/>resilient to change"]
style A fill:#FFEBEE,stroke:#D32F2F,color:#000
style B fill:#E3F2FD,stroke:#1976D2,color:#000
style C fill:#E8F5E9,stroke:#388E3C,color:#000
Definition: Five core principles of object-oriented design established by Robert C. Martin — Single Responsibility (SRP), Open/Closed (OCP), Liskov Substitution (LSP), Interface Segregation (ISP), and Dependency Inversion (DIP) — that guide the design of software that is easy to maintain and extend by lowering coupling and increasing cohesion.
Characteristics: (Mutually reinforcing principles) Each principle is independent yet mutually reinforcing, forming the foundation of clean architecture, DDD, and design patterns. (Indicator of code smell) Violations of these principles manifest as code smells and lead to technical debt. (Cost-benefit judgment) Excessive application can increase complexity, so a cost-benefit judgment is required.
2. Core Structure of the Five SOLID Principles
A. SRP, OCP, LSP
flowchart TD
subgraph R1[" "]
direction LR
SRP["SRP<br/>Single Responsibility Principle<br/>A class should have<br/>only one reason to change"]
OCP["OCP<br/>Open/Closed Principle<br/>Open for extension,<br/>closed for modification"]
LSP["LSP<br/>Liskov Substitution Principle<br/>A subclass must be fully<br/>substitutable for its parent class"]
end
style SRP fill:#E3F2FD,stroke:#1976D2,color:#000
style OCP fill:#F3E5F5,stroke:#7B1FA2,color:#000
style LSP fill:#FFF3E0,stroke:#F57C00,color:#000
style R1 fill:none,stroke:none
SRP — Single Responsibility Principle
| Category | Content |
|---|---|
| Principle | A class should have only one responsibility (one reason to change) |
| Violation example | UserService handles authentication, email sending, and DB storage all at once |
| Compliance approach | Split into AuthService, EmailService, and UserRepository |
| Effect | Minimizes the scope of change impact, clarifies test units |
OCP — Open/Closed Principle
| Category | Content |
|---|---|
| Principle | New functionality should be addable (extensible) without modifying existing code |
| Violation example | Repeated conditional branching such as if (type == "A") ... else if (type == "B") ... |
| Compliance approach | Apply the Strategy or Template Method pattern based on interfaces/abstract classes |
| Effect | Adding new requirements doesn’t require modifying existing code, preventing regression bugs |
LSP — Liskov Substitution Principle
| Category | Content |
|---|---|
| Principle | A subclass must honor the contract (preconditions/postconditions) of its parent class |
| Violation example | A Square subclassing Rectangle cannot independently change width and height (behavioral change) |
| Compliance approach | Verify the IS-A relationship, design inheritance without behavioral distortion |
| Effect | Enables safe use of polymorphism, prevents unexpected runtime errors |
B. Technical Characteristics of ISP and DIP
flowchart TD
subgraph R1[" "]
direction LR
ISP["ISP<br/>Interface Segregation Principle<br/>Clients should not depend<br/>on methods they don't use"]
DIP["DIP<br/>Dependency Inversion Principle<br/>High-level modules should not<br/>depend directly on low-level modules"]
end
style ISP fill:#FFEBEE,stroke:#D32F2F,color:#000
style DIP fill:#E8F5E9,stroke:#388E3C,color:#000
style R1 fill:none,stroke:none
ISP — Interface Segregation Principle
flowchart LR
subgraph BAD["ISP Violation (Fat Interface)"]
direction TB
FI["IWorker<br/>work / eat / sleep"]
R["Robot"] --> FI
H["Human"] --> FI
end
subgraph GOOD["ISP Compliance (Segregated Interfaces)"]
direction TB
IW["IWorkable<br/>work"]
IE["IEatable<br/>eat"]
IS["ISleepable<br/>sleep"]
R2["Robot"] --> IW
H2["Human"] --> IW
H2 --> IE
H2 --> IS
end
style BAD fill:#FFEBEE,stroke:#D32F2F,color:#B71C1C
style GOOD fill:#E8F5E9,stroke:#388E3C,color:#1B5E20
| Category | Content |
|---|---|
| Principle | Don’t force clients to depend on methods they don’t use |
| Violation example | IWorker includes work(), eat(), and sleep() together, forcing Robot to implement eat() |
| Compliance approach | Segregate into IWorkable, IEatable, and ISleepable interfaces |
| Effect | Removes unnecessary dependencies, minimizes the scope of interface-change impact |
DIP — Dependency Inversion Principle
flowchart LR
subgraph DIP_GOOD["DIP Compliance (Depending on Interfaces)"]
direction TB
UC["UseCase<br/>high-level module"] --> RI["Repository Interface<br/>abstraction"]
IMPL["JpaRepositoryImpl<br/>low-level implementation"] --> RI
end
style UC fill:#1E3A5F,stroke:#1E3A5F,color:#fff
style RI fill:#E3F2FD,stroke:#1976D2,color:#000
style IMPL fill:#E8F5E9,stroke:#388E3C,color:#000
| Category | Content |
|---|---|
| Principle | Both high-level and low-level modules should depend on abstractions (interfaces) |
| Violation example | OrderService directly creates and invokes MySQLOrderRepository |
| Compliance approach | Define an OrderRepository interface, swap implementations via dependency injection (DI) |
| Effect | No changes to business logic when switching technology stacks (MySQL → MongoDB), easy to swap in mocks for testing |
3. Expected Benefits and Application of the SOLID Principles
| Principle | Key Expected Benefit | Practical Application |
|---|---|---|
| SRP | Minimizes scope of change impact, improves testability | Limit class size, check responsibility separation based on method count |
| OCP | Extends functionality without modifying existing code | Use Strategy/Decorator patterns, design plugin architectures |
| LSP | Ensures safe polymorphism, prevents runtime errors | Verify IS-A relationships, favor composition over inheritance |
| ISP | Removes unnecessary dependencies, improves interface cohesion | Separate interfaces by role when designing APIs |
| DIP | Eases technology changes and swapping in test mocks | Use a dependency injection (DI) container such as Spring |