Strategy: đóng gói họ thuật toán bay và kêu của vịt

Định nghĩa Strategy, cấu trúc họ thuật toán hoán đổi được, và toàn bộ hành trình refactor SimUDuck từ kế thừa sụp đổ tới ủy thác linh hoạt.
Trung bìnhDesign pattern ~60 phút

Giới thiệu

Bài này học cách đóng gói họ thuật toán. Bạn đổi hành vi vịt ngay khi chạy.

Kiến thức cần nhớ

Strategy là gì

  • Gom mỗi thuật toán thành một lớp riêng.
  • Các lớp cùng họ đổi chỗ được cho nhau.
  • Ví dụ đời thường: thay lưỡi dao cùng một cán.
  • Lớp dùng chỉ gọi, không cần biết chi tiết.

Câu chuyện SimUDuck

  • Đầu tiên vịt kế thừa, vịt đồ chơi cũng biết bay sai.
  • Tách giao diện thì logic bay bị sao chép khắp nơi.
  • Strategy: vịt giữ 1 cách bay và 1 cách kêu.
  • Ví dụ đời thường: gắn động cơ khác vào cùng thân xe.

Đổi hành vi lúc chạy

  • Vịt gỗ gắn tên lửa là bay được ngay.
  • Thêm kiểu bay mới chỉ thêm lớp mới.
  • Lớp Vịt cũ không cần sửa chữ nào.
  • Ví dụ đời thường: đổi sim là đổi nhà mạng.
Cách làmThêm kiểu bay mới
Kế thừaSửa nhiều lớp
Giao diện thuầnSửa mọi lớp liên quan
StrategyThêm 1 lớp mới

Ví dụ

  • Input: vịt mồi đang đứng yên, gắn tên lửa. Output: cùng nút bay nay bay được.
  • Giải thích: chỉ thay đối tượng hành vi bên trong.

💻 Bài tập

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

Bài 1: SimUDuck với Strategy

Cài đặt đúng cấu trúc sau:

struct FlyBehavior   { virtual std::string fly() const = 0;   virtual ~FlyBehavior() = default; };
struct QuackBehavior { virtual std::string quack() const = 0; virtual ~QuackBehavior() = default; };

class Duck {
 public:
  Duck(std::unique_ptr<FlyBehavior> f, std::unique_ptr<QuackBehavior> q);
  std::string performFly() const;
  std::string performQuack() const;
  void setFlyBehavior(std::unique_ptr<FlyBehavior> f);   // đổi lúc chạy
  void setQuackBehavior(std::unique_ptr<QuackBehavior> q);
  virtual std::string display() const = 0;
  virtual ~Duck() = default;
};
Lớp cần viếtTrả về
FlyWithWings, FlyNoWay, FlyRocketPowered"bay bằng cánh", "không bay được", "bay bằng tên lửa"
Quack, Squeak, MuteQuack"quạc quạc", "chít chít", "..."
MallardDuck, RubberDuck, DecoyDuck, ModelDuckMỗi lớp chọn hành vi mặc định trong constructor
MallardDuck: performFly -> "bay bằng cánh", performQuack -> "quạc quạc"
RubberDuck:  performFly -> "không bay được", performQuack -> "chít chít"
ModelDuck:   performFly -> "không bay được"
ModelDuck.setFlyBehavior(FlyRocketPowered) -> performFly -> "bay bằng tên lửa"

Ràng buộc: lớp Duck không có if/switch theo loại vịt.

Bài 2: Refactor tính lương

Code ban đầu:

double salary(const std::string &type, double base, int hours, double sales) {
  if (type == "fulltime") return base;
  if (type == "parttime") return hours * 50000;
  if (type == "sales") return base * 0.5 + sales * 0.1;
  throw std::invalid_argument("unknown");
}

Yêu cầu: tạo interface PayPolicy với double pay(const Employee&) const. Viết 3 policy tương ứng. Employee giữ một PayPolicy. Sau đó thêm InternPolicy (lương cố định 3.000.000) mà không sửa code cũ.

fulltime base=15e6            -> 15000000
parttime hours=80             -> 4000000
sales base=10e6 sales=50e6    -> 10000000
intern                        -> 3000000

Bài 3: Nhân vật game đổi vũ khí (nâng cao)

Character có WeaponBehavior với int attack(int enemyArmor). Viết Sword (sát thương 30 trừ giáp), Bow (20, bỏ qua giáp), Magic (45 trừ 2 lần giáp, tối thiểu 5).

  1. Cho nhân vật đổi vũ khí giữa trận bằng setWeapon.
  2. Viết main mô phỏng 3 lượt đánh quái có giáp 10, mỗi lượt đổi vũ khí khác nhau. In sát thương từng lượt.
  3. Trong README.md, lập bảng so sánh: thêm vũ khí thứ 4 bằng kế thừa (SwordKnight, BowKnight...) tốn bao nhiêu lớp so với Strategy.
Sword vs armor 10 -> 20
Bow   vs armor 10 -> 20
Magic vs armor 10 -> 25
Magic vs armor 30 -> 5

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

  • Toàn bộ test mẫu pass.
  • Không có chuỗi if/switch chọn hành vi trong Duck, Employee, Character.
  • Thêm hành vi mới chỉ tạo file mới, không sửa file cũ.
  • Vẽ sơ đồ lớp (tay hoặc Mermaid) có quan hệ "has-a" tới 2 họ hành vi.

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

  • Strategy là gì, nói 1 câu?
  • Vì sao kế thừa gây bay nhầm ở vịt cao su?
  • Đổi hành vi lúc chạy nghĩa là gì?
  • Khi nào nên dùng Strategy?

🌕 Bạn đã hoàn thành ngày 6. 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.