MVC: compound pattern điều khiển nhịp DJ
Mô hình khung nhìn điều khiển qua ứng dụng nhịp DJ, cách ba tầng nói chuyện và compound pattern là gì.
KhóDesign pattern ~60 phút
Ôn lại trước khi học
Giới thiệu
Bài này học tách dữ liệu, hiển thị và điều khiển riêng. Dùng để thêm màn hình mới không sửa ruột cũ.
Kiến thức cần nhớ
Compound và 3 tầng
- Định nghĩa: compound là cụm pattern cùng giải 1 bài.
- Model giữ nhịp nhạc và luật đổi nhịp.
- View chỉ hiển thị số và đèn chớp theo nhịp.
- Ví dụ đời thường: như DJ, loa, nút vặn riêng nhau.
- Controller nhận nút bấm rồi gọi model đổi.
Luồng người dùng
- DJ bấm tăng nhịp trên controller.
- Controller gọi model đổi nhịp mới.
- Model báo cho mọi view đang nghe.
- Ví dụ đời thường: như vặn nút rồi loa đổi theo.
- Thêm view mới chỉ cần đăng ký nghe model.
| Tầng | Việc duy nhất | Không làm việc |
|---|---|---|
| Model | Giữ nhịp và luật | Không vẽ màn hình |
| View | Vẽ theo số mới | Không tự đổi số |
| Controller | Nhận nút bấm | Không giữ dữ liệu |
Luồng nhịp đập
- Model tự sinh nhịp đều đặn theo giờ.
- Mỗi nhịp báo cho các view đang nghe.
- View đèn chớp 1 cái, view số giữ nguyên.
- Ví dụ đời thường: như metronome gõ đều cho band.
- Model không biết có mấy view đang nghe.
MVC trên web
- Ứng dụng web chia MVC qua request: trình duyệt gửi request tới controller, controller gọi model, rồi chọn view để dựng trang trả về.
- Khác MVC trên máy: view thường không đăng ký nghe model trực tiếp (Observer), mà nhận dữ liệu mỗi lần controller dựng trang.
Ví dụ
- Input: bấm tăng từ 100 lên 120 -> Output: số và đèn cùng đổi.
- Giải thích: model đổi 1 lần, mọi view tự vẽ lại.
# Controller gọi model, model báo view
model.set_nhip(120) # đổi dữ liệu
for v in views: # báo từng view
v.ve_lai(model.nhip)
💻 Bài tập
Ngôn ngữ: C++17 (hoặc Java). Giao diện dạng console, cập nhật bằng in lại dòng. Nộp vào day-107/.
Bài 1: Model nhịp DJ
struct BeatObserver { virtual void updateBeat() = 0; virtual ~BeatObserver() = default; };
struct BPMObserver { virtual void updateBPM() = 0; virtual ~BPMObserver() = default; };
class BeatModel {
public:
void on(); void off();
void setBPM(int bpm); // kẹp trong [40, 240]
int getBPM() const;
void tick(); // gọi từ vòng lặp thời gian, báo mọi BeatObserver
void registerObserver(BeatObserver*); void registerObserver(BPMObserver*);
void removeObserver(BeatObserver*); void removeObserver(BPMObserver*);
};
setBPM(120) -> mọi BPMObserver nhận updateBPM, getBPM = 120
setBPM(500) -> getBPM = 240
off() -> BPM = 0, tick không phát
Bài 2: View và Controller
| Thành phần | Việc phải làm |
|---|---|
DJView | Đăng ký cả 2 loại observer. In "BPM: 120" và 1 ký tự * mỗi nhịp |
BeatController | Nhận lệnh start, stop, +, -, set N từ bàn phím. Gọi model. Bật tắt nút trên view (in trạng thái nút) |
| Strategy | View chỉ gọi controller, controller có thể thay bằng lớp khác |
start; + ; + ; + ; set 90; stop
-> BPM: 60 -> 61 -> 62 -> 63 -> 90 -> 0, nút Start/Stop đổi trạng thái đúng
Thêm BPMGraphView in thanh # dài theo BPM. Không sửa BeatModel.
Bài 3: Tái dùng view với model khác (nâng cao)
- Viết
HeartModelcó interface khác (getHeartRate(), observer riêng). - Viết
HeartAdapterđểDJViewdùng đượcHeartModel. - Viết
HeartController(không cho đổi nhịp tim: lệnh+,-bị bỏ qua, in cảnh báo). - Liệt kê trong
README.md: MVC này dùng những pattern nào, ở đâu (Observer, Strategy, Composite nếu có, Adapter).
✅ Tiêu chí hoàn thành
- Test model pass (kẹp BPM, bật tắt, observer).
- Thêm view mới không sửa model.
-
DJViewchạy vớiHeartModelqua adapter. - Bảng pattern trong MVC chỉ đúng vị trí trong code.
❓ Câu hỏi ôn tập
- Model giữ cái gì?
- View có được đổi số không?
- Ai nhận nút bấm?
- Thêm view có sửa model không?
🌕 Bạn đã hoàn thành ngày 107. Làm hết bài tập phía trên rồi sang ngày tiếp theo.