Bridge và Builder còn lại nhưng quan trọng

Bridge tách trừu tượng khỏi cài đặt cho remote TV, Builder dựng bữa ăn từng bước thay vì constructor khổng lồ.
KhóDesign pattern ~60 phút

Giới thiệu

Bài này học Bridge tách điều khiển khỏi thiết bị và Builder dựng từng bước. Dùng để thêm hãng TV hay món ăn không vỡ code.

Kiến thức cần nhớ

Bridge

  • Định nghĩa: tách trừu tượng khỏi cài đặt qua một cầu.
  • Remote giữ một cầu tới TV, bấm nút là chuyển lời.
  • Ví dụ đời thường: như remote đa năng bấm là TV chạy.
  • Thêm hãng TV mới chỉ thêm 1 lớp.
  • Không nhân số lớp theo tích hai chiều.
Cách làmThêm hãng mớiThêm remote mới
Kế thừa liệt kêNhân thêm nhiều lớpNhân thêm nhiều lớp
Bridge qua cầuChỉ 1 lớp TVChỉ 1 lớp remote

Builder

  • Định nghĩa: dựng đối tượng phức tạp qua từng bước nhỏ.
  • Thay constructor khổng lồ nhiều tham số rối rắm.
  • Ví dụ đời thường: như gọi cơm chọn từng món một.
  • Mỗi bước trả về chính builder để nối chuỗi.
  • Bước cuối gọi build để ra thành phẩm.
# Builder dựng bữa ăn từng bước
meal = (MealBuilder()
    .them_mon_chinh("cơm gà")  # chọn món chính
    .them_nuoc("trà đá")  # chọn nước
    .build())  # chốt đơn
print(meal)

Khi nào dùng

  • Dùng Bridge khi hai chiều cùng thay đổi độc lập.
  • Dùng Builder khi đối tượng có quá nhiều tùy chọn.
  • Không dùng Bridge cho quan hệ một chiều đơn giản.
  • Không dùng Builder cho object chỉ 1-2 field.

Ví dụ

  • Input: thêm hãng TV thứ 4 -> Output: chỉ thêm 1 lớp TV mới.
  • Giải thích: remote cũ giữ nguyên vì chỉ nói qua cầu.
  • Input: bữa ăn thiếu nước -> Output: builder báo thiếu trước khi build.
  • Giải thích: từng bước kiểm tra rõ hơn constructor dài.

💻 Bài tập

Ngôn ngữ: C++17 (hoặc Java). Nộp vào day-092/.

Bài 1: Bridge cho remote và TV

struct TV {   // implementor
  virtual void on() = 0; virtual void off() = 0; virtual void tuneChannel(int ch) = 0;
  virtual int channel() const = 0; virtual ~TV() = default;
};
class RemoteControl {   // abstraction
 protected: TV &tv;
 public:
  explicit RemoteControl(TV &t);
  virtual void on(); virtual void off(); virtual void setChannel(int ch);
  virtual ~RemoteControl() = default;
};
class ConcreteRemote : public RemoteControl {
 public: void nextChannel(); void previousChannel(); void favorite(int slot); void setFavorite(int slot, int ch);
};

TV cụ thể: SonyTV, SamsungTV, LgTV (kênh hợp lệ khác nhau: Sony 1-99, Samsung 1-999, LG 1-500; kênh sai thì ném lỗi).

ConcreteRemote(SonyTV).setChannel(5); nextChannel() -> Sony kênh 6
ConcreteRemote(SonyTV).setChannel(99); nextChannel() -> quay vòng về 1

Đếm số lớp cần viết với kế thừa thuần (mỗi loại remote x mỗi hãng) và với Bridge, khi có 3 loại remote và 3 hãng TV. Ghi vào README.md.

Bài 2: Builder cho đối tượng nhiều tùy chọn

class HttpRequest { /* method, url, headers, query, body, timeoutMs, retries */ };
class HttpRequestBuilder {
 public:
  explicit HttpRequestBuilder(std::string url);
  HttpRequestBuilder &method(std::string m);
  HttpRequestBuilder &header(std::string k, std::string v);
  HttpRequestBuilder &query(std::string k, std::string v);
  HttpRequestBuilder &body(std::string b);
  HttpRequestBuilder &timeout(int ms);
  HttpRequestBuilder &retries(int n);
  HttpRequest build() const;   // kiểm tra hợp lệ
};
Luật kiểm tra trong build()Lỗi
GET có bodyinvalid_argument
timeout <= 0 hoặc retries < 0invalid_argument
URL không bắt đầu bằng http:// hoặc https://invalid_argument

Viết HttpRequest::toString() in dạng request HTTP thô. Test 5 request hợp lệ và 3 request lỗi.

Bài 3: Kết hợp và phản biện (nâng cao)

  1. Viết ReportBuilder dựng báo cáo gồm tiêu đề, các mục, bảng. Kết hợp Bridge: báo cáo xuất qua Renderer (MarkdownRenderer, HtmlRenderer).
  2. So HttpRequestBuilder với constructor 7 tham số và với struct có designated initializers C++20. Viết 3 câu: khi nào Builder đáng giá, khi nào không.

✅ Tiêu chí hoàn thành

  • Test Bridge pass với 3 hãng TV.
  • Bảng số lớp kế thừa thuần vs Bridge.
  • Builder kiểm tra đủ 3 luật, có test lỗi.
  • Bài 3 có phản biện Builder bằng code thật.

❓ Câu hỏi ôn tập

  • Bridge tách cái gì khỏi cái gì?
  • Vì sao kế thừa liệt kê gây bùng nổ lớp?
  • Builder thay thế nỗi đau nào?
  • Khi nào không nên dùng Builder?

🌕 Bạn đã hoàn thành ngày 92. Làm hết bài tập phía trên rồi sang ngày tiếp theo.

Bớt paste mù, hiểu sâu từng dòng mình viết.

180 Days Challenge. 180 ngày cai nghiện vibe code.