Template Method: khung pha chế và Hollywood principle
Ôn lại trước khi học
Giới thiệu
Bài này học Template Method giữ khung chung cho nhiều món. Khung này giúp thêm món mới mà không sửa code cũ.
Kiến thức cần nhớ
Khung giữ cấu trúc
- Template Method là khung thuật toán nằm ở lớp cha.
- Lớp con chỉ điền bước riêng, không đổi thứ tự.
- Ví dụ đời thường: khuôn làm bánh quyết định các bước chung.
- Dùng khi nhiều quy trình giống nhau 80%.
Trà và cà phê bốn bước
- Cả hai cùng trình tự: đun, pha, rót, thêm gia vị.
- Đun và rót giống nhau nên viết sẵn ở lớp cha.
- Pha và thêm gia vị khác nhau nên để lớp con viết.
- Ví dụ đời thường: trà hãm lá, cà phê pha phin.
# Khung pha chế: cha giữ thứ tự, con điền bước
class DoUong:
def pha_che(self): # khung 4 bước cố định
self.dun_nuoc() # bước chung viết sẵn
self.pha() # bước riêng con tự viết
self.rot() # bước chung viết sẵn
if self.muốn_gia_vi(): # móc treo hỏi ý
self.them_gia_vi()
Móc treo và Hollywood
- Móc treo là bước có sẵn đáp án mặc định.
- Lớp con có thể ghi đè hoặc bỏ qua móc.
- Hollywood: con ngồi chờ, khung gọi đúng lúc.
- Ví dụ đời thường: khách kiêng đường thì bỏ qua bước đường.
| Khía cạnh | Bước trừu tượng | Móc treo |
|---|---|---|
| Lớp con | Bắt buộc viết | Tùy chọn ghi đè |
| Khung có sẵn | Không có | Có đáp án mặc định |
| Dùng khi | Bước nào cũng khác | Hiếm khi ngoại lệ |
Ví dụ
- Input: pha trà chanh -> Output: 4 bước chạy đủ, gia vị là chanh.
- Câu này cho thấy bước chung và riêng phối hợp.
- Input: pha cà phê kiêng đường -> Output: bỏ bước đường, 3 bước còn lại chạy.
- Câu này cho thấy móc treo giúp bỏ qua linh hoạt.
💻 Bài tập
Ngôn ngữ: C++17 (hoặc Java). Nộp vào day-034/. Mỗi bước ghi vào std::vector<std::string> log để test thứ tự.
Bài 1: Trà và cà phê
class CaffeineBeverage {
public:
void prepareRecipe(); // final: đun, pha, rót, (móc) thêm gia vị
const std::vector<std::string> &log() const;
virtual ~CaffeineBeverage() = default;
protected:
virtual void brew() = 0;
virtual void addCondiments() = 0;
virtual bool customerWantsCondiments() { return true; } // hook
private:
void boilWater(); void pourInCup();
};
| Lớp | brew() | addCondiments() |
|---|---|---|
Tea | "ngâm trà" | "thêm chanh" |
Coffee | "lọc cà phê" | "thêm đường và sữa" |
CoffeeWithHook nhận bool wantSugar qua constructor và ghi đè hook.
Tea -> [đun nước, ngâm trà, rót ra cốc, thêm chanh]
Coffee -> [đun nước, lọc cà phê, rót ra cốc, thêm đường và sữa]
CoffeeWithHook(false) -> [đun nước, lọc cà phê, rót ra cốc]
Ràng buộc: prepareRecipe không virtual (hoặc final trong Java). Lớp con không đổi được thứ tự.
Bài 2: Khung xử lý file dữ liệu
Viết DataImporter::run(path) với các bước cố định: open → parseLine cho từng dòng → validate → save → report. Hook bool skipHeader() mặc định true.
Viết CsvImporter (tách bằng dấu phẩy) và TsvImporter (tách bằng tab). Dòng không hợp lệ bị bỏ qua và đếm lại.
users.csv có 1 header + 4 dòng, 1 dòng thiếu cột -> report: "3 hợp lệ, 1 lỗi"
Bài 3: Hollywood trong sắp xếp (nâng cao)
std::sort là một Template Method: khung sắp xếp cố định, bạn chỉ cung cấp phép so sánh.
- Tự viết
template<class T> void mySort(std::vector<T>&, bool (*less)(const T&, const T&))(insertion sort). Dùng chostruct Duck { std::string name; int weight; }sắp theo cân nặng. - Viết 3 câu trong
README.md: điểm giống và khác giữa cách này và Template Method dùng kế thừa. - So sánh Template Method với Strategy: bảng 3 dòng (cơ chế, lúc nào đổi được hành vi, ai giữ khung).
✅ Tiêu chí hoàn thành
- Test thứ tự log Bài 1 pass cho cả 3 lớp.
- Bài 2: thêm
JsonLinesImporterchỉ cần 1 file mới. - Bài 3 có bảng so sánh với Strategy.
- Giải thích được nguyên lý Hollywood bằng một ví dụ trong code của mình.
❓ Câu hỏi ôn tập
- Template Method giữ cái gì và nhả cái gì?
- Hai bước nào của trà và cà phê giống nhau?
- Móc treo khác bước trừu tượng thế nào?
- Hollywood principle nghĩa là ai gọi ai?
🌕 Bạn đã hoàn thành ngày 34. Làm hết bài tập phía trên rồi sang ngày tiếp theo.