[Java Backend Zero to Hello] BÀI 6.4: SOLID PRINCIPLES
📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 6: REST API & Best Practices | Bài 63/86
BÀI 6.4: SOLID PRINCIPLES
Mục tiêu
- Hiểu 5 nguyên lý SOLID
- Áp dụng vào thiết kế class
- Viết code dễ bảo trì, mở rộng
1. SOLID LÀ GÌ?
SOLID là 5 nguyên lý thiết kế hướng đối tượng, giúp code:
- Dễ hiểu
- Dễ bảo trì
- Dễ mở rộng
- Giảm coupling
- Tăng cohesion
| Chữ cái | Nguyên lý |
|---|---|
| S | Single Responsibility |
| O | Open/Closed |
| L | Liskov Substitution |
| I | Interface Segregation |
| D | Dependency Inversion |
2. S - SINGLE RESPONSIBILITY PRINCIPLE (SRP)
Một class chỉ nên có một lý do để thay đổi.
❌ Vi phạm
public class UserService {
public User createUser(User user) { ... }
public void sendEmail(User user) { ... } // ❌ Nhiều trách nhiệm
public void generateReport() { ... } // ❌
public void saveToDatabase(User user) { ... } // ❌
}
✅ Tuân thủ
public class UserService {
private final UserRepository repository;
private final EmailService emailService;
public User createUser(User user) {
User saved = repository.save(user);
emailService.sendWelcome(saved);
return saved;
}
}
public class EmailService {
public void sendWelcome(User user) { ... }
}
public class ReportService {
public void generateReport() { ... }
}
3. O - OPEN/CLOSED PRINCIPLE (OCP)
Class nên mở rộng được nhưng đóng với việc sửa đổi.
❌ Vi phạm
public class PaymentService {
public void process(String type) {
if (type.equals("CREDIT_CARD")) {
// Xử lý thẻ tín dụng
} else if (type.equals("MOMO")) {
// Xử lý MoMo
} else if (type.equals("BANK_TRANSFER")) {
// Xử lý chuyển khoản
}
// Mỗi lần thêm payment mới phải sửa class
}
}
✅ Tuân thủ
public interface PaymentProcessor {
void process(Payment payment);
}
@Service
public class CreditCardProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}
@Service
public class MomoProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}
@Service
public class BankTransferProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}
@Service
@RequiredArgsConstructor
public class PaymentService {
private final List<PaymentProcessor> processors;
public void process(Payment payment) {
processors.stream()
.filter(p -> p.supports(payment.getMethod()))
.findFirst()
.orElseThrow()
.process(payment);
}
}
4. L - LISKOV SUBSTITUTION PRINCIPLE (LSP)
Object của class con có thể thay thế object của class cha mà không làm thay đổi tính đúng đắn.
❌ Vi phạm
public class Bird {
public void fly() { ... }
}
public class Penguin extends Bird {
@Override
public void fly() {
throw new UnsupportedOperationException(); // ❌ Vi phạm LSP
}
}
✅ Tuân thủ
public abstract class Bird {
public abstract void move();
}
public class Sparrow extends Bird {
@Override
public void move() {
fly();
}
private void fly() { ... }
}
public class Penguin extends Bird {
@Override
public void move() {
swim();
}
private void swim() { ... }
}
Ví dụ thực tế với Rectangle/Square
// ❌ Vi phạm
public class Rectangle {
protected int width, height;
public void setWidth(int w) { width = w; }
public void setHeight(int h) { height = h; }
public int area() { return width * height; }
}
public class Square extends Rectangle {
@Override
public void setWidth(int w) {
width = w;
height = w; // ❌ Thay đổi hành vi
}
}
// ✅ Tuân thủ
public interface Shape {
int area();
}
public class Rectangle implements Shape {
private int width, height;
// ...
}
public class Square implements Shape {
private int side;
// ...
}
5. I - INTERFACE SEGREGATION PRINCIPLE (ISP)
Client không nên bị ép buộc phụ thuộc vào interface mà họ không sử dụng.
❌ Vi phạm
public interface Animal {
void fly();
void swim();
void run();
}
public class Dog implements Animal {
public void fly() { throw new UnsupportedOperationException(); } // ❌
public void swim() { ... }
public void run() { ... }
}
✅ Tuân thủ
public interface Flyable {
void fly();
}
public interface Swimmable {
void swim();
}
public interface Runnable {
void run();
}
public class Dog implements Swimmable, Runnable {
public void swim() { ... }
public void run() { ... }
}
public class Bird implements Flyable, Runnable {
public void fly() { ... }
public void run() { ... }
}
6. D - DEPENDENCY INVERSION PRINCIPLE (DIP)
Module cấp cao không nên phụ thuộc module cấp thấp. Cả hai nên phụ thuộc abstraction.
❌ Vi phạm
public class UserService {
private final MySQLUserRepository repository = new MySQLUserRepository();
// Phụ thuộc trực tiếp vào implementation
}
✅ Tuân thủ
public interface UserRepository {
User findById(Long id);
User save(User user);
}
@Repository
public class MySQLUserRepository implements UserRepository {
public User findById(Long id) { ... }
public User save(User user) { ... }
}
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository repository; // Phụ thuộc abstraction
}
7. VÍ DỤ TỔNG HỢP
7.1 Hệ thống đặt hàng
// Domain
public class Order {
private Long id;
private List<OrderItem> items;
private OrderStatus status;
// ...
}
// Repository (DIP)
public interface OrderRepository {
Order save(Order order);
Optional<Order> findById(Long id);
}
// Service (SRP)
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository orderRepository;
private final PaymentProcessor paymentProcessor;
private final NotificationService notificationService;
@Transactional
public Order createOrder(CreateOrderRequest request) {
Order order = Order.from(request);
Order saved = orderRepository.save(order);
paymentProcessor.process(saved);
notificationService.sendConfirmation(saved);
return saved;
}
}
// Payment (OCP)
public interface PaymentProcessor {
boolean supports(PaymentMethod method);
void process(Order order);
}
@Service
public class CreditCardProcessor implements PaymentProcessor {
public boolean supports(PaymentMethod method) {
return method == PaymentMethod.CREDIT_CARD;
}
public void process(Order order) { ... }
}
// Notification (ISP)
public interface NotificationService {
void sendConfirmation(Order order);
}
@Service
public class EmailNotificationService implements NotificationService {
public void sendConfirmation(Order order) { ... }
}
8. BÀI TẬP THỰC HÀNH
Bài 1: Refactor UserService
Tách UserService thành nhiều class theo SRP.
Bài 2: Payment System
Thiết kế hệ thống thanh toán với OCP.
Bài 3: Notification
Tạo interface Notification theo ISP.
9. TÓM TẮT
| Nguyên lý | Mô tả |
|---|---|
| SRP | Một class, một trách nhiệm |
| OCP | Mở rộng, đóng sửa đổi |
| LSP | Thay thế được bằng class cha |
| ISP | Interface nhỏ, chuyên biệt |
| DIP | Phụ thuộc abstraction |
Bài tiếp theo: 6.5 Design Patterns
🧭 Điều Hướng Series
⬅️ Bài trước: BÀI 6.3: DTO & MAPPER
📋 Lộ trình tổng quan: Xem Toàn Bộ Series
➡️ Bài tiếp theo: BÀI 6.5: DESIGN PATTERNS THƯỜNG GẶP
All rights reserved