Bài 7 · Nâng cao · 22 phút· Cập nhật 11/06/2026
Ứng dụng SOLID vào thực tế
Biên soạn bởi Nguyễn Anh Tuấn
Áp dụng cả 5 nguyên tắc SOLID vào một ví dụ checkout hoàn chỉnh: xem các nguyên tắc củng cố lẫn nhau ra sao, cân bằng để tránh over-engineering.
Năm nguyên tắc không tách rời - chúng cùng xuất hiện trong một thiết kế tốt. Lấy một hệ thống đặt hàng (checkout) làm ví dụ. Trước hết là các abstraction:
Các abstraction - ISP (nhỏ, chuyên biệt) + DIP (nghiệp vụ chỉ biết interface)
interface PaymentMethod { pay(amount: number): void; } // OCP: them phuong thuc = them lop
interface OrderRepository { save(order: Order): void; } // DIP: nghiep vu biet interface
interface Notifier { notify(message: string): void; } // ISP: interface nho, mot viec Rồi các chi tiết cấp thấp - mỗi lớp tự lo phần của nó, và thay thế nhau được:
Implementation - SRP (mỗi lớp một việc) + LSP (đều thay thế được)
class CardPayment implements PaymentMethod {
pay(amount: number) { /* tinh phi the */ }
}
class MoMoPayment implements PaymentMethod {
pay(amount: number) { /* goi API MoMo */ }
}
class SqlOrderRepo implements OrderRepository {
save(order: Order) { /* INSERT ... */ }
}
class EmailNotifier implements Notifier {
notify(message: string) { /* gui email */ }
} Lớp nghiệp vụ cấp cao chỉ ghép các bước, phụ thuộc vào abstraction và nhận implementation từ ngoài:
CheckoutService - SRP (chỉ điều phối) + DIP (tiêm abstraction)
class CheckoutService {
constructor(
private payment: PaymentMethod, // DIP: tiem qua constructor
private orders: OrderRepository,
private notifier: Notifier,
) {}
checkout(order: Order): void {
this.payment.pay(order.total); // khong biet Card hay MoMo (OCP + LSP)
this.orders.save(order);
this.notifier.notify("Da dat hang thanh cong");
}
}
// Diem lap rap (composition root): chon implementation o MOT noi
const checkout = new CheckoutService(
new MoMoPayment(),
new SqlOrderRepo(),
new EmailNotifier(),
); - ▸Đổi MoMo → Card, SQL → Mongo, Email → SMS: chỉ sửa ở điểm lắp ráp.
- ▸CheckoutService test được bằng cách tiêm các bản giả (fake).
- ▸Thêm phương thức thanh toán mới không cần đụng CheckoutService.
| S | Mỗi lớp một việc: CardPayment chỉ thanh toán, EmailNotifier chỉ báo tin, CheckoutService chỉ điều phối. |
| O | Thêm ZaloPayPayment = thêm một lớp; không sửa CheckoutService. |
| L | Mọi PaymentMethod giữ đúng hợp đồng pay() → thay thế nhau không phá luồng. |
| I | Notifier / PaymentMethod / OrderRepository là các interface nhỏ, không ép ai implement method thừa. |
| D | CheckoutService phụ thuộc abstraction; implementation được tiêm từ composition root. |
Củng cố lẫn nhau
- ▸YAGNI: chưa cần thì chưa trừu tượng hoá - để thay đổi THỰC TẾ kéo abstraction ra đời.
- ▸Mỗi abstraction có giá: thêm lớp, thêm gián tiếp, khó lần theo luồng.
- ▸SOLID + Clean Code (vi mô) + Design Pattern (lời giải mẫu) bổ trợ nhau.
- ▸Mục tiêu cuối: phần mềm dễ thay đổi với chi phí thấp - không phải "đếm đủ 5 chữ".
La bàn, không phải bản đồ chi tiết
Chạy lại bộ tình huống - giờ bạn đã học cả 5 nguyên tắc, hãy xem mình nhận diện nhanh tới đâu:
🔍 Đoán xem: vi phạm nguyên tắc nào?
1/10Câu hỏi thường gặp
Chúng đan vào nhau quanh một mục tiêu chung - giảm phụ thuộc cứng. SRP tách trách nhiệm; ISP tách interface (SRP cho hợp đồng); OCP cho phép mở rộng nhờ đa hình; LSP bảo đảm các biến thể thật sự thay thế được; DIP đảo chiều phụ thuộc để nghiệp vụ độc lập với chi tiết. Làm tốt cái này thường kéo theo cái kia.
Phần lớn design pattern chính là SOLID được áp dụng cụ thể: Strategy (OCP), Factory/Dependency Injection (DIP), Adapter (ISP/DIP), Template Method (OCP/LSP)... Hiểu SOLID rồi học pattern sẽ thấy "à, hoá ra là vậy" thay vì học vẹt.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Phần lớn các design pattern thực ra là gì?
- 1
Bản đồ nguyên tắc
Lấy ví dụ
CheckoutServiceở Bước 1-2. Với mỗi chữ S-O-L-I-D, chỉ ra nó thể hiện ở dòng/phần nào.✅ Hoàn thành khi: Gắn đúng cả 5 nguyên tắc vào các phần cụ thể của code.
- 2
Thêm phương thức thanh toán
Thêm
ZaloPayPaymentvào ví dụ mà KHÔNG sửaCheckoutService- chứng minh OCP + DIP đang hoạt động.✅ Hoàn thành khi: Chỉ thêm một lớp mới;
CheckoutServicegiữ nguyên; lắp ở composition root. - 3
Áp dụng vào module của mèo con
Chọn một module nhỏ trong dự án và refactor để thể hiện ít nhất 3 trong 5 nguyên tắc.
✅ Hoàn thành khi: Nêu rõ trước/sau; chỉ ra 3 nguyên tắc đã áp dụng và lợi ích thu được.
- 4
Vạch ranh giới YAGNI
Trong chính refactor trên, nêu một chỗ em CỐ TÌNH không trừu tượng hoá và giải thích vì sao (tránh over-engineering).
✅ Hoàn thành khi: Quyết định có lý do; cân bằng được giữa SOLID và KISS/YAGNI.