Simple Factory: đóng gói khởi tạo đối tượng pizza
Vì sao từ khóa tạo mới gây cứng nhắc, cách gom khởi tạo vào một xưởng đơn giản qua câu chuyện Pizza Store.
Trung bìnhDesign pattern ~60 phút
Ôn lại trước khi học
Giới thiệu
Bài này học cách gom chỗ tạo đối tượng. Bạn không rải lệnh tạo khắp nơi nữa.
Kiến thức cần nhớ
Rải lệnh tạo gây cứng
- Mỗi nhánh gọi thẳng 1 lớp pizza cụ thể.
- Thêm loại mới phải mở cửa hàng ra sửa.
- Đổi tên lớp cũng phải sửa cửa hàng.
- Ví dụ đời thường: mỗi chi nhánh tự nặn công thức.
Xưởng đơn giản gom lại
- Mọi cách tạo dồn vào 1 xưởng chung.
- Cửa hàng hỏi xưởng, nhận pizza chung.
- Cửa hàng chạy 4 bước chuẩn không cần biết loại.
- Ví dụ đời thường: kho tổng phát hàng cho chi nhánh.
Giới hạn của xưởng đơn
- Thêm chiều vùng miền thì xưởng phình to.
- Pizza cùng tên mà New York khác Chicago.
- Lúc đó cần Factory Method bài sau.
- Ví dụ đời thường: 1 kho không cân 2 miền vị khác.
| Tiêu chí | Rải khắp nơi | Qua xưởng |
|---|---|---|
| Biết lớp cụ thể | Rải trong cửa hàng | Gom trong xưởng |
| Thêm loại mới | Mở cửa hàng sửa | Sửa đúng xưởng |
| Dùng lại | Sao chép khối lệnh | Dùng chung xưởng |
Ví dụ
- Input: khách gọi pizza phô mai. Output: xưởng trả đúng loại, cửa hàng chạy đủ 4 bước.
- Giải thích: kiến thức lớp cụ thể nằm 1 chỗ duy nhất.
💻 Bài tập
Ngôn ngữ: C++17 (hoặc Java). Nộp vào day-018/.
Bài 1: Pizza Store với Simple Factory
class Pizza {
public:
virtual std::string name() const = 0;
virtual void prepare(); virtual void bake(); virtual void cut(); virtual void box();
const std::vector<std::string> &log() const; // ghi lại các bước để test
virtual ~Pizza() = default;
};
class SimplePizzaFactory { public: std::unique_ptr<Pizza> create(const std::string &type) const; };
class PizzaStore {
public:
explicit PizzaStore(const SimplePizzaFactory &f);
std::unique_ptr<Pizza> order(const std::string &type); // create + 4 bước
};
| Loại | name() |
|---|---|
"cheese" | "Pizza phô mai" |
"pepperoni" | "Pizza xúc xích" |
"veggie" | "Pizza rau" |
"clam" | "Pizza nghêu" |
Ràng buộc
PizzaStorekhông#includelớp pizza cụ thể nào.- Loại không tồn tại:
createtrảnullptr,ordernémstd::invalid_argument.
order("cheese") -> name "Pizza phô mai", log = [prepare, bake, cut, box]
order("sushi") -> ném invalid_argument
Bài 2: Thêm loại mới
- Thêm
"seafood"và chứng minh chỉSimplePizzaFactoryvà file lớp mới thay đổi. - Đổi
createsang bảng đăng ký:std::unordered_map<std::string, std::function<std::unique_ptr<Pizza>()>>. Thêm hàmregisterType(name, creator). Thêm loại mới lúc chạy mà không sửa factory.
Bài 3: Xưởng tài liệu (nâng cao)
DocumentFactory::create(path) chọn lớp theo đuôi file: .txt ra TextDocument, .csv ra SpreadsheetDocument, .md ra MarkdownDocument. Mỗi lớp có std::string summary().
TextDocument: số dòng, số từ.SpreadsheetDocument: số hàng, số cột.MarkdownDocument: số heading#.
Đuôi không hỗ trợ thì trả lỗi rõ ràng. Viết main nhận danh sách file từ dòng lệnh và in summary() từng file.
✅ Tiêu chí hoàn thành
- Test mẫu pass.
-
PizzaStorekhông phụ thuộc lớp cụ thể (kiểm tra bằng#include). - Bảng đăng ký cho phép thêm loại lúc chạy.
- Giải thích được giới hạn của Simple Factory khi có thêm chiều vùng miền.
❓ Câu hỏi ôn tập
- Vì sao rải lệnh tạo khắp nơi lại xấu?
- Xưởng đơn giản làm gì?
- Quy trình pizza gồm 4 bước nào?
- Khi nào xưởng đơn không đủ?
🌕 Bạn đã hoàn thành ngày 18. Làm hết bài tập phía trên rồi sang ngày tiếp theo.