SOLID là 5 nguyên tắc thiết kế OOP (Robert C. Martin): S Single Responsibility, O Open/Closed, L Liskov Substitution, I Interface Segregation, D Dependency Inversion.
S — Single Responsibility: Một class chỉ có một lý do để thay đổi. Không phải "1 class = 1 method" mà là "1 class = 1 trục thay đổi".
// ❌ Vi phạm: class đổi vì 3 lý do khác nhau
class User {
void save() { /* DB */ } // đổi khi DB schema đổi
void sendWelcomeEmail() { /* SMTP */ } // đổi khi email provider đổi
String renderHtml() { /* HTML */ } // đổi khi UI đổi
}
// ✅ Tách theo trách nhiệm
class User { /* data + business invariant */ }
class UserRepository { void save(User u) {} }
class WelcomeEmailService { void send(User u) {} }O — Open/Closed: Module nên mở để mở rộng, đóng để sửa đổi. Thêm feature bằng thêm code, không sửa code cũ.
// ❌ Vi phạm: mỗi shape mới phải sửa method này
double area(Object shape) {
if (shape instanceof Circle c) return Math.PI * c.radius * c.radius;
if (shape instanceof Square s) return s.side * s.side;
// thêm Hexagon → phải sửa
}
// ✅ Open qua polymorphism
interface Shape { double area(); }
class Circle implements Shape { /* ... */ }
class Hexagon implements Shape { /* ... */ } // thêm mới — code cũ không đụngCông cụ đạt OCP: polymorphism, strategy pattern, DI container.
Lưu ý: OCP không có nghĩa "mọi class đều phải mở mở rộng" — premature abstraction là anti-pattern. Mở khi có lý do rõ (đã sửa nhiều lần hoặc biết trước nhiều biến thể).
SOLID is 5 OOP design principles (Robert C. Martin): S Single Responsibility, O Open/Closed, L Liskov Substitution, I Interface Segregation, D Dependency Inversion.
S — Single Responsibility: A class should have only one reason to change. Not "1 class = 1 method" but "1 class = one axis of change".
// ❌ Violation: this class changes for 3 different reasons
class User {
void save() { /* DB */ } // changes with DB schema
void sendWelcomeEmail() { /* SMTP */ } // changes with email provider
String renderHtml() { /* HTML */ } // changes with UI
}
// ✅ Split by responsibility
class User { /* data + business invariants */ }
class UserRepository { void save(User u) {} }
class WelcomeEmailService { void send(User u) {} }O — Open/Closed: Modules should be open for extension, closed for modification. Add features by adding code, not changing existing code.
// ❌ Violation: every new shape forces this method to change
double area(Object shape) {
if (shape instanceof Circle c) return Math.PI * c.radius * c.radius;
if (shape instanceof Square s) return s.side * s.side;
// add Hexagon → must edit
}
// ✅ Open via polymorphism
interface Shape { double area(); }
class Circle implements Shape { /* ... */ }
class Hexagon implements Shape { /* ... */ } // new — old code untouchedTools for OCP: polymorphism, strategy pattern, DI containers.
Caveat: OCP does not mean "every class must be extensible" — premature abstraction is an anti-pattern. Open it when you have clear reasons (repeated past edits or known variants).