86. SOLID Principles
SOLID is five object-oriented design principles — Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion — that guide writing maintainable, extensible Java code.
Java 21 (core language)Explanation
S — Single Responsibility Principle: a class should have one reason to change. A class that does persistence AND formatting AND validation is hard to change any one of them safely.
O — Open/Closed Principle: open for extension (new behaviours via subclassing or composition), closed for modification (existing code need not change). Achieved with interfaces, abstract classes, and Strategy/Decorator patterns.
L — Liskov Substitution Principle: a subtype must be substitutable for its supertype without altering the correctness of the program. Violations: a Square overriding setWidth of Rectangle and silently changing height breaks callers that use the Rectangle contract.
I — Interface Segregation Principle: no client should be forced to implement methods it does not need. Split fat interfaces into smaller, focused ones.
D — Dependency Inversion Principle: high-level modules should not depend on low-level modules — both should depend on abstractions. Don't new up your collaborators; inject the interface.
Example
// S: each class has one responsibility
class ReportFormatter { String format(String data) { return "<html>" + data + "</html>"; } }
class ReportPersistor { void save(String report) { System.out.println("Saved: " + report); } }
// O: open for extension (add new Shapes), closed for modification
interface AreaCalc { double area(); }
record OCircle(double r) implements AreaCalc { public double area() { return Math.PI*r*r; } }
record OSquare(double s) implements AreaCalc { public double area() { return s*s; } }
// L: subtype is fully substitutable
interface Bird { void eat(); }
interface FlyingBird extends Bird { void fly(); }
class Eagle implements FlyingBird { public void eat(){} public void fly(){ System.out.println("Eagle flies"); } }
class Penguin implements Bird { public void eat(){} } // doesn't implement fly — LSP OK
// I: small focused interfaces
interface Readable { String read(); }
interface Writable { void write(String s); }
interface ReadWrite extends Readable, Writable {} // composed when needed
// D: depend on abstraction, not concrete class
interface Logger { void log(String msg); }
class ConsoleLogger implements Logger { public void log(String msg) { System.out.println("[LOG] " + msg); } }
class OrderProcessor {
private final Logger logger; // interface, not ConsoleLogger
OrderProcessor(Logger logger) { this.logger = logger; }
void process(String order) { logger.log("Processing: " + order); }
}
public class SolidPrinciples {
public static void main(String[] args) {
// S
var formatter = new ReportFormatter();
var persistor = new ReportPersistor();
persistor.save(formatter.format("sales data"));
// O
for (AreaCalc shape : new AreaCalc[]{ new OCircle(5), new OSquare(4) }) {
System.out.printf("Area: %.2f%n", shape.area());
}
// L
Bird eagle = new Eagle();
if (eagle instanceof FlyingBird fb) fb.fly();
new Penguin().eat(); // no fly — correct
// D
OrderProcessor proc = new OrderProcessor(new ConsoleLogger());
proc.process("order-001");
}
}Sources
- https://en.wikipedia.org/wiki/SOLID — SOLID principles overview
- https://www.pearson.com/en-us/subject-catalog/p/effective-java/P200000000138 — Effective Java (OO design guidance throughout)