Đàn vịt compound: 4 patterns trong một app

Mô phỏng vịt dùng chung Strategy Observer Decorator Factory, đếm tiếng quạc và đàn vịt an toàn.
KhóDesign pattern ~60 phút

Ôn lại trước khi học

Giới thiệu

Bài này học ghép 4 pattern trong 1 app vịt. Dùng để đếm tiếng kêu không sửa lớp vịt cũ.

Kiến thức cần nhớ

Strategy và Decorator

  • Strategy: mỗi vịt giữ kiểu kêu và bay riêng.
  • Decorator đếm: bọc vịt thật, kêu thì tăng đếm 1.
  • Ví dụ đời thường: như đeo vòng đếm bước không mổ xẻ.
  • Không sửa lớp vịt nào mà vẫn đếm được.
  • Kêu thật trước, tăng đếm ngay sau đó.

Factory và Composite

  • Factory đếm: xưởng tạo vịt đã bọc sẵn bộ đếm.
  • Khách gọi xưởng như gọi vịt thường mỗi ngày.
  • Composite đàn: đàn là 1 vịt chứa nhiều vịt con.
  • Gọi kêu trên đàn thì cả đàn cùng kêu.
  • Ví dụ đời thường: như hô 1 lớp là cả lớp thưa.
PatternViệc trong appVí như
StrategyGiữ kiểu kêu bayTính cách mỗi vịt
DecoratorĐếm tiếng kêuVòng đếm bước
FactoryTạo vịt đã bọcDây chuyền đóng gói
CompositeGom đàn vịtLớp học nhiều tổ

Observer

  • Định nghĩa: nhà nghiên cứu đăng ký nghe từng vịt.
  • Mỗi tiếng quạc là 1 tin báo tự động tới.
  • Ví dụ đời thường: như follow kênh là nhận tin mới.
  • Thêm người nghe không sửa code vịt cũ.
  • Đàn kêu thì mỗi con báo riêng 1 tin.

Ví dụ

  • Input: đàn 3 vịt kêu 1 lượt -> Output: đếm tổng tăng 3.
  • Giải thích: mỗi bộ bọc tăng 1 rồi cộng dồn lại.
# Bộ đếm bọc ngoài vịt thật
class DemQuac:
    def keu(self):
        self.vit.keu()  # vịt trong kêu
        DemQuac.tong += 1  # tăng đếm chung

💻 Bài tập

Ngôn ngữ: C++17 (hoặc Java). Nộp vào day-108/. Bài này xây dần từng pattern, mỗi bước 1 commit.

Bài 1: Vịt, ngỗng và đếm tiếng kêu

struct Quackable { virtual std::string quack() = 0; virtual ~Quackable() = default; };
BướcViệc phải làmPattern
1MallardDuck, RedheadDuck, DuckCall, RubberDuck cài Quackable
2Goose có honk(). Viết GooseAdapter để ngỗng vào được đànAdapter
3QuackCounter bọc 1 Quackable, mỗi lần kêu tăng biến đếm staticDecorator
4AbstractDuckFactory với CountingDuckFactory trả vịt đã bọc bộ đếmAbstract Factory
Tạo 4 vịt qua CountingDuckFactory + 1 GooseAdapter không bọc đếm
Mỗi con kêu 1 lần -> QuackCounter::count() = 4 (ngỗng không được đếm)

Bài 2: Đàn vịt và người quan sát

BướcViệc phải làmPattern
5Flock : Quackable chứa std::vector<std::shared_ptr<Quackable>>. quack() gọi mọi conComposite
6Iterator duyệt đàn (có thể dùng iterator của std::vector)Iterator
7QuackObservable với registerObserver, notifyObservers. Quackologist in "Nhà nghiên cứu: <tên> vừa kêu"Observer
Đàn lớn = 3 vịt + đàn vịt trời (4 con) -> quack() -> đếm tăng 7
Nhà nghiên cứu đăng ký cả đàn lớn -> nhận đúng 7 tin, mỗi tin ghi tên vịt thật (không phải "QuackCounter")
Khi QuackCounter bọc vịt, tin báo phải mang tên vịt bên trong. Hãy để decorator chuyển lời registerObserver vào vịt được bọc.

Bài 3: Nhìn lại (nâng cao)

  1. Vẽ sơ đồ lớp cả hệ thống (Mermaid classDiagram), đánh dấu 6 pattern.
  2. Viết 1 câu cho mỗi pattern: vấn đề nó giải quyết trong bài này.
  3. Phản biện: đâu là chỗ dùng pattern thừa nếu yêu cầu chỉ là "đếm tiếng kêu của 5 con vịt"? Viết bản tối giản và so số dòng.

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

  • Mỗi bước có 1 commit, test của bước trước vẫn pass.
  • Test đếm và test tin báo của Bài 2 pass.
  • Sơ đồ lớp đánh dấu đủ 6 pattern.
  • Có phản biện và bản tối giản.

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

  • Ai đếm tiếng quạc?
  • Xưởng tạo ra hàng gì?
  • Đàn kêu thì ai kêu?
  • Tin báo gửi tới ai?

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