SOLID Principles — Design Foundation
SOLID is an acronym for 5 object-oriented design principles that produce flexible, maintainable, and testable code. They are the philosophical foundation behind all GoF design patterns and modern frameworks.
SOLID — All Five Principles with Examples
// ─── S: Single Responsibility Principle ──────────────────────
// A class should have exactly one reason to change.
// ❌ Violates SRP — handles data, formatting, AND persistence
class BookBad {
void save() { /* SQL logic here */ }
String toHtml() { /* HTML formatting here */ }
void validate() { /* validation here */ }
}
// ✅ SRP — each class has one job
class Book { /* Just models a book */ }
class BookRepository { void save(Book b) { /* DB logic */ } }
class BookHtmlRenderer { String render(Book b) { /* HTML */ } }
class BookValidator { void validate(Book b) { /* validation */ } }
// ─── O: Open/Closed Principle ─────────────────────────────────
// Classes should be OPEN for extension, CLOSED for modification.
// ❌ Violates OCP — must modify class to add a new fee calculation
class FeeCalculatorBad {
double calculate(String memberType, double price) {
if (memberType.equals("PREMIUM")) return price * 0.8;
else return price; // add new type → modify this class
}
}
// ✅ OCP — add new strategies without touching existing code
interface FeeStrategy { double calculate(double price); }
class StandardFee implements FeeStrategy { public double calculate(double p) { return p; } }
class PremiumFee implements FeeStrategy { public double calculate(double p) { return p * 0.8; } }
class StudentFee implements FeeStrategy { public double calculate(double p) { return p * 0.5; } }
// ─── L: Liskov Substitution Principle ─────────────────────────
// Subtypes must be substitutable for their base types (no surprises).
// ❌ Violates LSP — ReadOnlyBook can't fulfill Book's contract
class Book { void borrow() { available = false; } }
class ReadOnlyBook extends Book {
@Override
void borrow() { throw new UnsupportedOperationException(); } // unexpected!
}
// ✅ LSP — refactor with interfaces based on capabilities
interface Borrowable { void borrow(); void returnItem(); }
interface Viewable { String getTitle(); String getContent(); }
class LendableBook implements Borrowable, Viewable { /* */ }
class ReferenceBook implements Viewable { /* */ } // no borrow capability
// ─── I: Interface Segregation Principle ───────────────────────
// Clients should not be forced to depend on interfaces they don't use.
// ❌ Violates ISP — one fat interface
interface LibraryItem {
void borrow(); void returnItem();
String stream(); // only makes sense for digital items
void reservePhysical(); // only makes sense for physical books
}
// ✅ ISP — split into focused interfaces
interface Physical { void borrow(); void returnItem(); void reservePhysical(); }
interface Digital { String stream(); void download(); }
class PrintedBook implements Physical { /* */ }
class Ebook implements Physical, Digital { /* */ }
class AudioBook implements Digital { /* */ }
// ─── D: Dependency Inversion Principle ───────────────────────
// Depend on abstractions, not concretions.
// ❌ Violates DIP — LibraryService coupled to SqlBookRepo directly
class LibraryServiceBad {
private SqlBookRepository repo = new SqlBookRepository(); // hard-coded dependency
}
// ✅ DIP — depend on the interface; inject the implementation
interface BookRepository { Optional<Book> findByIsbn(String isbn); void save(Book b); }
class LibraryService {
private final BookRepository repo; // abstraction
LibraryService(BookRepository repo) { this.repo = repo; } // injected
}
// Now you can inject SqlBookRepository, InMemoryBookRepository, or MockBookRepositoryQuick Quiz
Tip
Tip
Practice SOLID Principles Design Foundation in small, isolated examples before integrating into larger projects. Breaking concepts into small experiments builds genuine understanding faster than reading alone.
Understand when and why to use each pattern. Singleton often overused — prefer DI. Builder for complex object creation.
Practice Task
Note
Practice Task — (1) Write a working example of SOLID Principles Design Foundation from scratch without looking at notes. (2) Modify it to handle an edge case (empty input, null value, or error state). (3) Share your solution in the Priygop community for feedback.
Common Mistake
Warning
A common mistake with SOLID Principles Design Foundation is skipping edge case testing — empty inputs, null values, and unexpected data types. Always validate boundary conditions to write robust, production-ready java code.