Tổ chức patterns C/S/B và anti-patterns
Ôn lại trước khi học
Giới thiệu
Bài này học bản đồ 3 nhóm pattern và 4 anti-pattern. Bạn dùng nó để chọn pattern nhanh và tránh code rối.
Kiến thức cần nhớ
Ba nhóm pattern
- Tạo sinh: lo cách tạo đối tượng, ví dụ Factory, Singleton.
- Cấu trúc: lo cách lắp đối tượng, ví dụ Decorator, Adapter.
- Hành vi: lo cách đối tượng nói chuyện, ví dụ Strategy, Observer.
- Ví dụ đời thường: như xây nhà có đội làm gạch, đội lắp khung, đội chia việc.
Bảng tra cứu nhanh
- Muốn đổi thuật toán lúc chạy thì Strategy.
- Muốn một đổi nhiều nghe thì Observer.
- Muốn bọc thêm việc thì Decorator.
- Ví dụ đời thường: như tra từ điển, có nhu cầu là có pattern.
| Nhu cầu | Pattern |
|---|---|
| Đổi thuật toán lúc chạy | Strategy |
| Lan tin một nhiều | Observer |
| Gom hệ con nhiều bước | Facade |
| Duyệt mà giấu cách lưu | Iterator |
Anti-patterns
- Lớp chúa: một lớp ôm mọi việc, sửa một chỗ lan khắp nơi.
- Mì Ý: luồng code rối như tô mì, đọc không biết đầu cuối.
- Sao chép dán: cùng logic ở chục nơi, sửa sót chỗ này chỗ kia.
- Vàng mạ: làm hoành tráng cho yêu cầu chưa tới.
- Ví dụ đời thường: lớp chúa như một người vừa nấu vừa thu tiền vừa giữ xe.
Khi nào không dùng pattern
- Bài toán chỉ cần 1 lớp và 1 vòng lặp là đủ.
- Chỉ có 1 biến thể và không đổi suốt lịch sử.
- Thêm pattern khiến đọc 1 việc phải nhảy qua 5 lớp.
- Ví dụ đời thường: như đi chợ gần nhà thì đi bộ, không cần thuê xe tải.
Phân loại thêm và cách tư duy theo pattern
- Ngoài 3 nhóm tạo sinh, cấu trúc, hành vi, pattern còn chia theo phạm vi: pattern lớp (quan hệ cố định lúc biên dịch qua kế thừa, ví dụ Factory Method, Template Method, class Adapter) và pattern đối tượng (quan hệ lắp ghép lúc chạy qua hợp thành, phần lớn các pattern còn lại).
- Tiến trình tư duy thường gặp: người mới thấy pattern ở khắp nơi; người trung cấp biết khi nào cần và khi nào không; người thành thạo chỉ dùng pattern khi nó là lời giải tự nhiên nhất.
- Giữ thiết kế đơn giản trước. Chỉ thêm pattern khi có thay đổi thật đang đòi hỏi, không phải thay đổi tưởng tượng.
Ví dụ
- Input: nhu cầu đổi thuật toán lúc chạy. Output: chọn Strategy.
- Giải thích: Strategy cho phép hoán đổi thuật toán mà không sửa lớp dùng.
- Input: cùng logic copy ở 5 nơi. Output: gom về 1 chỗ duy nhất.
- Giải thích: hết mùi sao chép dán, sửa 1 lần là xong.
💻 Bài tập
Ngôn ngữ: C++17 (hoặc Java). Nộp vào day-064/. Bài này nặng về đọc và refactor code.
Bài 1: Bảng tra pattern
Viết patterns.md gồm 1 bảng cho mọi pattern đã học tới ngày 64 (Strategy, Observer, Decorator, Simple Factory, Singleton, Adapter, Factory Method, Command, Facade, Template Method, Iterator). Mỗi dòng có 5 cột:
| Pattern | Nhóm (C/S/B) | Vấn đề giải quyết (1 câu) | Dấu hiệu nhận biết trong code | Ngày đã học |
|---|
Thêm 6 tình huống, mỗi tình huống chọn đúng 1 pattern và viết 1 câu lý do:
- Ứng dụng cần xuất báo cáo PDF, Excel, CSV, sau này còn thêm loại khác.
- Thư viện thanh toán bên thứ ba có API khác interface của bạn.
- Mỗi khi đơn hàng đổi trạng thái, cần báo cho kho, email, thống kê.
- Nút "Hoàn tác" cho trình soạn thảo.
- Cần thêm nén và mã hóa vào luồng ghi file, bật tắt tùy ý.
- Khởi động hệ thống cần gọi 8 dịch vụ con theo đúng thứ tự.
Bài 2: Tháo "lớp chúa"
Tự viết (hoặc lấy từ code cũ của bạn) lớp OrderManager khoảng 200 dòng, có ít nhất: tính giá có giảm giá bằng switch, lưu file, gửi email, ghi log, in hóa đơn.
- Liệt kê các anti-pattern có trong đó: lớp chúa, sao chép dán, mì Ý.
- Refactor bằng pattern phù hợp. Mỗi thay đổi ghi 1 dòng: pattern gì, sửa vấn đề gì.
- Viết test giữ nguyên hành vi trước và sau refactor (cùng input, cùng output).
Bài 3: Khi nào không dùng pattern (nâng cao)
Cho đoạn code "vàng mạ" sau (tự viết lại đầy đủ):
struct GreeterFactory { virtual std::unique_ptr<Greeter> create() = 0; };
struct Greeter { virtual std::string greet(const std::string &name) = 0; };
struct DefaultGreeterFactory : GreeterFactory { ... };
struct DefaultGreeter : Greeter { ... }; // chỉ có đúng 1 cài đặt, 3 năm chưa đổi
- Viết lại thành 1 hàm. So số dòng.
- Viết 5 câu: khi nào cấu trúc cũ đáng giá, khi nào không.
✅ Tiêu chí hoàn thành
-
patterns.mdđủ 11 pattern và 6 tình huống. - Bài 2 có test trước/sau refactor pass với cùng dữ liệu.
- Bài 3 có phiên bản rút gọn và lập luận rõ ràng.
- Nêu được 4 anti-pattern bằng lời của mình.
❓ Câu hỏi ôn tập
- Ba nhóm pattern là gì?
- Muốn đổi thuật toán lúc chạy thì dùng gì?
- Lớp chúa và mì Ý là bệnh gì?
- Khi nào không nên dùng pattern?
🌕 Bạn đã hoàn thành ngày 64. Làm hết bài tập phía trên rồi sang ngày tiếp theo.