So sánh 3 factory và nghịch lý mở rộng
Ôn lại trước khi học
Giới thiệu
Bài này học cách chọn giữa 3 loại factory. Bạn dùng nó để không thiết kế thừa cho bài toán nhỏ.
Kiến thức cần nhớ
Hành trình Pizza Store
- Nấc 1: rẽ nhánh tạo pizza trong thân cửa hàng.
- Nấc 2: gom vào xưởng đơn giản, cửa hàng sạch nhưng xưởng phình.
- Nấc 3: mỗi chi nhánh tự tạo pizza vùng mình theo khung chung.
- Nấc 4: gom nguyên liệu thành xưởng theo họ cho nhất quán.
- Ví dụ đời thường: như quán nhỏ 1 bếp, lớn dần mới cần nhiều bếp chuyên.
Bảng so sánh
- Xưởng đơn giản: 1 món theo tên gọi, xưởng trung tâm quyết.
- Factory Method: 1 product, lớp con quyết định.
- Abstract Factory: cả họ product, xưởng từng họ quyết.
| Tiêu chí | Đơn giản | Method | Abstract |
|---|---|---|---|
| Tạo ra | 1 món | 1 product | Cả họ |
| Thêm họ mới | Sửa xưởng | Thêm lớp mới | Thêm xưởng mới |
| Thêm món mới | Sửa 1 chỗ | Thêm từng vùng | Sửa mọi xưởng |
Nghịch lý mở rộng
- Mọi thiết kế dễ theo 1 chiều và khó theo chiều còn lại.
- Thêm họ mới thì Method và Abstract dễ, code cũ nguyên vẹn.
- Thêm món mới vào Abstract rất đau vì sửa mọi xưởng.
- Phải cược vào chiều nào hay đổi hơn theo lịch sử dự án.
Cây quyết định
- Không có họ biến thể thì tạo trực tiếp cho gọn.
- Logic tạo lặp nhiều nơi thì xưởng đơn giản là đủ.
- Có khung chung mà khâu tạo đổi theo biến thể thì Method.
- Sản phẩm phải đi cùng họ nhất quán thì Abstract.
Ví dụ
- Input: thêm vùng mới vào hệ Factory Method. Output: khung cũ nguyên vẹn, vùng mới chạy đúng quy trình.
- Giải thích: thêm creator mới không chạm khung.
- Input: thêm món mới vào hệ Abstract Factory. Output: phải sửa giao diện và mọi xưởng.
- Giải thích: không có cách thêm mà không chạm code cũ.
💻 Bài tập
Ngôn ngữ: C++17 (hoặc Java). Nộp vào day-075/. Bài này là so sánh có code minh họa.
Bài 1: Bốn nấc tiến hóa
Viết 4 thư mục step1/ tới step4/, cùng làm 1 việc: cửa hàng bán pizza cheese và clam cho 2 vùng NY và Chicago.
| Thư mục | Cách tạo đối tượng |
|---|---|
step1/ | if/else lồng nhau theo vùng và loại, ngay trong orderPizza |
step2/ | Simple Factory nhận (vùng, loại) |
step3/ | Factory Method: mỗi chi nhánh ghi đè createPizza |
step4/ | Factory Method + Abstract Factory nguyên liệu |
Mỗi bước có cùng 1 file test order_test.cpp và cho cùng output.
Bài 2: Đo chi phí thay đổi
Áp 3 thay đổi lên cả 4 bước. Mỗi thay đổi đếm số file và số dòng bị sửa bằng git diff --stat:
- Thêm loại pizza
veggie. - Thêm vùng
California. - Thêm nguyên liệu mới
Pepperonicho mọi vùng.
thay_đổi step1 step2 step3 step4
thêm veggie ... files ...
thêm California ...
thêm Pepperoni ...
Viết 5 câu kết luận: mỗi pattern dễ theo chiều nào, khó theo chiều nào.
Bài 3: Chọn pattern cho tình huống (nâng cao)
Với mỗi tình huống, chọn: tạo trực tiếp, Simple Factory, Factory Method, Abstract Factory. Viết 2 câu lý do và phác thảo interface (5-10 dòng code):
- Ứng dụng đọc ảnh PNG, JPEG, WebP theo đuôi file.
- Thư viện kiểm thử cho phép người dùng tự định nghĩa cách tạo test fixture.
- Game có 3 chủng tộc, mỗi chủng tộc có lính, nhà, vũ khí riêng phải đi cùng nhau.
- Tạo
std::vector<int>rỗng. - Driver cơ sở dữ liệu: MySQL, Postgres, SQLite, mỗi loại có Connection, Statement, ResultSet.
✅ Tiêu chí hoàn thành
- 4 bước cùng pass 1 file test.
- Bảng đo chi phí thay đổi có số thật từ
git diff --stat. - Bài 3 có lựa chọn và interface cho cả 5 tình huống.
- Phân biệt được 3 loại factory bằng 1 câu mỗi loại.
❓ Câu hỏi ôn tập
- Ba factory khác nhau ở đối tượng tạo ra là gì?
- Nghịch lý mở rộng nghĩa là gì?
- Khi nào xưởng đơn giản là đủ?
- Dấu hiệu nào báo cần nâng lên Method hay Abstract?
🌕 Bạn đã hoàn thành ngày 75. Làm hết bài tập phía trên rồi sang ngày tiếp theo.