State nâng cao: game 1/10 và State vs Strategy

Trạng thái trúng thưởng đổi sơ đồ chuyển, chia sẻ trạng thái giữa nhiều máy, và ranh giới với Strategy.
KhóDesign pattern ~60 phút

Giới thiệu

Bài này học thêm trạng thái trúng thưởng và phân biệt State. Bạn dùng nó để mở rộng máy kẹo không vỡ code.

Kiến thức cần nhớ

Trạng thái trúng thưởng

  • Game 1 phần 10 lượt quay trúng 2 viên thay vì 1.
  • Thêm 1 lớp trúng thưởng, sửa đúng 1 chỗ ở đã nhận xu.
  • Quay thì bốc thăm: trúng sang trúng thưởng, trượt sang đã bán.
  • Trúng thưởng nhả 2 viên rồi về chờ hoặc hết tùy tồn kho.

Sơ đồ 5 trạng thái

  • Chờ nhận xu thì sang đã nhận.
  • Đã nhận quay thì bốc thăm, trả xu thì về chờ.
  • Trúng nhả 2 viên, bán nhả 1 viên rồi về chờ hoặc hết.
  • Hết kẹo từ chối mọi thứ tới khi nạp lại.
  • Vẽ sơ đồ ra giấy là có tài liệu sống cho cả nhóm.

Chia sẻ trạng thái

  • Đối tượng trạng thái không giữ gì riêng ngoài máy đang phục vụ.
  • Nhiều máy dùng chung 1 bộ 5 trạng thái cho nhẹ.
  • Mỗi máy chỉ đổi tham chiếu sang trạng thái chung tương ứng.
  • Trăm máy cũng chỉ cần 5 đối tượng trạng thái.
Tiêu chíStrategyState
Ai chọnKhách ngoài gắn vàoNội tại tự chuyển
Mục đíchĐổi thuật toán theo ý dùngĐổi hành vi theo vòng đời
Quan hệ biến thểĐộc lậpBiết nhau qua sơ đồ

Ví dụ

  • Input: quay trúng khi còn nhiều kẹo. Output: nhả 2 viên, tồn giảm 2, về chờ.
  • Giải thích: trúng thưởng nhả đôi rồi quay về vòng mới.
  • Input: quay trúng nhưng chỉ còn 1 viên. Output: nhả 1 viên duy nhất, sang hết kẹo.
  • Giải thích: không nợ viên thứ 2, lượt sau từ chối xu.

💻 Bài tập

Ngôn ngữ: C++17 (hoặc Java). Dùng tiếp GumballMachine ngày 85. Nộp vào day-086/.

Bài 1: Game 1/10 trúng thưởng

Thêm WinnerState. Trong HasQuarterState::turnCrank(), bốc thăm: 10% sang WinnerState (nếu còn ít nhất 2 viên), còn lại sang SoldState.

Yêu cầuChi tiết
Bốc thămNhận std::function<int()> rng qua constructor máy để test được
WinnerNhả 2 viên. Còn kẹo thì về NoQuarter, hết thì SoldOut
Còn đúng 1 viênKhông được vào WinnerState
rng luôn trúng, máy 5 viên: mua 1 lần -> còn 3
rng luôn trúng, máy 1 viên: mua 1 lần -> còn 0, không vào Winner
rng thật, 10.000 lượt mua, máy nạp lại liên tục -> tỉ lệ trúng ~ 10%

Chứng minh bằng git diff --stat: chỉ HasQuarterState và file mới WinnerState thay đổi (cộng dòng đăng ký trong máy).

Bài 2: Dùng chung đối tượng trạng thái

  1. Biến 5 trạng thái thành không lưu dữ liệu riêng: mọi hàm nhận GumballMachine& làm tham số thay vì giữ con trỏ.
  2. Tạo 100 máy dùng chung 5 đối tượng trạng thái static. In số đối tượng trạng thái được tạo (phải là 5).
  3. Viết 3 câu: đánh đổi giữa trạng thái giữ tham chiếu máy và trạng thái dùng chung.

Bài 3: State và Strategy (nâng cao)

  1. Viết bảng so sánh 2 pattern: ai chọn đối tượng hành vi, ai đổi nó, lúc nào đổi, sơ đồ lớp có giống nhau không.
  2. Viết 1 ví dụ Strategy trên chính máy kẹo: chính sách giá (NormalPrice, HappyHour giảm 50%). Người vận hành đặt từ bên ngoài.
  3. Viết GumballMonitor in báo cáo: vị trí máy, số kẹo, tên trạng thái. Dùng lại ở ngày 98 (Proxy).

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

  • Test trúng thưởng pass với rng giả.
  • Thêm Winner chỉ sửa 1 trạng thái cũ.
  • 100 máy chỉ dùng 5 đối tượng trạng thái.
  • Bảng State vs Strategy có ví dụ code cho cả hai.

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

  • Thêm trúng thưởng phải sửa mấy chỗ?
  • Chia sẻ trạng thái tiết kiệm gì?
  • Câu hỏi nhanh phân biệt State và Strategy là gì?
  • Khi nào không nên dùng State?

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