86 lines
3.6 KiB
Markdown
86 lines
3.6 KiB
Markdown
# SOLID Principles — Overview
|
|
|
|
The SOLID principles are five design guidelines that make object-oriented software easier to understand, maintain, and extend. They were promoted by Robert C. Martin (Uncle Bob) and have become foundational to professional software engineering.
|
|
|
|
## Quick-Reference Table
|
|
|
|
| Principle | Abbr. | One-Liner | Key Question |
|
|
|---|---|---|---|
|
|
| **Single Responsibility** | SRP | A class should have only one reason to change. | "Does this class do more than one job?" |
|
|
| **Open/Closed** | OCP | Open for extension, closed for modification. | "Can I add behavior without editing existing code?" |
|
|
| **Liskov Substitution** | LSP | Subtypes must be substitutable for their base types. | "Can I swap in a subclass without breaking anything?" |
|
|
| **Interface Segregation** | ISP | No client should depend on methods it does not use. | "Is any implementer forced to stub out unused methods?" |
|
|
| **Dependency Inversion** | DIP | Depend on abstractions, not concretions. | "Does my high-level logic import low-level details?" |
|
|
|
|
## Decision Tree
|
|
|
|
Use the following decision tree when reviewing or designing code:
|
|
|
|
```
|
|
START: You are looking at a class / module / struct
|
|
│
|
|
├─ Does it have more than one reason to change?
|
|
│ YES → Apply SRP. Split into focused units.
|
|
│ NO ↓
|
|
│
|
|
├─ To add a new variant / behavior, must you edit existing code?
|
|
│ YES → Apply OCP. Introduce polymorphism or strategy.
|
|
│ NO ↓
|
|
│
|
|
├─ Can every subtype replace its parent without breaking callers?
|
|
│ NO → Apply LSP. Fix the inheritance hierarchy or use composition.
|
|
│ YES ↓
|
|
│
|
|
├─ Are implementers forced to depend on methods they don't use?
|
|
│ YES → Apply ISP. Break the interface into smaller, focused ones.
|
|
│ NO ↓
|
|
│
|
|
├─ Do high-level modules import / instantiate low-level concretions?
|
|
│ YES → Apply DIP. Introduce an abstraction and inject dependencies.
|
|
│ NO ↓
|
|
│
|
|
└─ Design looks solid. Review for other concerns (DRY, KISS, etc.)
|
|
```
|
|
|
|
## How the Principles Relate
|
|
|
|
```
|
|
SRP ──► keeps units small and focused
|
|
│
|
|
OCP ──► lets you extend those units safely
|
|
│
|
|
LSP ──► guarantees substitutability in those extensions
|
|
│
|
|
ISP ──► prevents bloated contracts between units
|
|
│
|
|
DIP ──► decouples the wiring so everything stays flexible
|
|
```
|
|
|
|
- **SRP + ISP** often work together: splitting a fat class (SRP) usually means splitting its interface too (ISP).
|
|
- **OCP + DIP** are natural partners: depending on abstractions (DIP) is *how* you achieve extension without modification (OCP).
|
|
- **LSP** is the safety net: it ensures that the polymorphism you rely on for OCP actually works correctly.
|
|
|
|
## When to Apply SOLID
|
|
|
|
**Apply aggressively when:**
|
|
- The codebase is long-lived and maintained by a team
|
|
- Requirements change frequently
|
|
- You are building libraries or frameworks consumed by others
|
|
- Testability is a priority
|
|
|
|
**Apply with restraint when:**
|
|
- Writing a one-off script or prototype
|
|
- The domain is tiny and unlikely to change
|
|
- Over-abstraction would add complexity without benefit
|
|
- You are in the earliest exploratory phase of a project
|
|
|
|
## Files in This Directory
|
|
|
|
| File | Principle |
|
|
|---|---|
|
|
| [single-responsibility.md](single-responsibility.md) | Single Responsibility Principle |
|
|
| [open-closed.md](open-closed.md) | Open/Closed Principle |
|
|
| [liskov-substitution.md](liskov-substitution.md) | Liskov Substitution Principle |
|
|
| [interface-segregation.md](interface-segregation.md) | Interface Segregation Principle |
|
|
| [dependency-inversion.md](dependency-inversion.md) | Dependency Inversion Principle |
|