0

[Java Backend Zero to Hello] BÀI 6.4: SOLID PRINCIPLES

Java Backend Zero to Hello

📚 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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí