Observer nâng cao: pull vs push và trạm thời tiết
Ôn lại trước khi học
Giới thiệu
Bài này học 2 cách truyền tin đẩy và kéo. Bạn chọn đúng cách cho từng bảng.
Kiến thức cần nhớ
Đẩy — gửi cả gói
- Trạm gửi kèm toàn bộ số đo trong tin báo.
- Bảng nhận 1 bước là đủ, khỏi hỏi lại.
- Nhược điểm là bảng nào cũng nhận thừa.
- Ví dụ đời thường: phát cả tờ báo dù chỉ đọc 1 tin.
Kéo — báo rồi tự lấy
- Trạm chỉ báo tin ngắn đã đổi.
- Bảng cần gì thì tới lấy đúng phần đó.
- Thêm chỉ số mới không làm bảng cũ hỏng.
- Ví dụ đời thường: tin nhắn có hàng, tới lấy món mình.
Cờ đã đổi và hàng dựng sẵn
- Số mới giống số cũ thì khỏi báo.
- Cờ đã đổi giúp tránh vẽ lại vô ích.
- Hàng dựng sẵn nhanh nhưng khóa cứng và khó đổi.
- Ví dụ đời thường: giá không đổi thì khỏi hét.
| Tiêu chí | Đẩy | Kéo |
|---|---|---|
| Số bước | 1 bước nhận đủ | 2 bước báo rồi lấy |
| Nhận thừa | Hay thừa | Chỉ lấy phần cần |
| Thêm chỉ số mới | Nhiều bảng phải sửa | Bảng cũ nguyên vẹn |
Ví dụ
- Input: số mới khác số cũ, 3 bảng đang nghe. Output: cả 3 kéo đúng phần mình và vẽ lại.
- Giải thích: trạm dựng cờ rồi báo tin ngắn.
💻 Bài tập
Ngôn ngữ: C++17 (hoặc Java). Nộp vào day-015/. Dùng lại trạm thời tiết ngày 9.
Bài 1: Chuyển trạm từ đẩy sang kéo
struct Observer { virtual void update(Subject &changed) = 0; virtual ~Observer() = default; };
class WeatherData : public Subject {
public:
float temperature() const; float humidity() const; float pressure() const;
void setMeasurements(float t, float h, float p);
};
| Yêu cầu | Chi tiết |
|---|---|
| Chỉ báo tin ngắn | update(*this), observer tự gọi getter cần thiết |
Cờ changed | setChanged() bật cờ; notifyObservers() chỉ báo khi cờ bật rồi tắt cờ |
| Bỏ qua thay đổi nhỏ | setMeasurements chỉ setChanged() khi nhiệt độ lệch ít nhất 0.5 độ so với lần báo trước |
set(26.0, 65, 1012) -> báo
set(26.3, 66, 1012) -> KHÔNG báo (lệch 0.3)
set(26.6, 66, 1011) -> báo
Bài 2: Thêm chỉ số không khí
Thêm int aqi() const vào WeatherData và AirQualityDisplay in cảnh báo khi aqi > 150.
Yêu cầu: 3 display cũ không sửa dòng nào. Trong README.md chứng minh bằng git diff --stat. Viết thêm 3 câu: nếu vẫn dùng kiểu đẩy update(t, h, p) thì phải sửa những gì.
Bài 3: Một bảng nghe hai trạm (nâng cao)
IndoorOutdoorDisplay đăng ký cả indoor và outdoor. Khi update(Subject &s) được gọi, bảng phân biệt nguồn bằng so sánh địa chỉ và in chênh lệch nhiệt độ trong-ngoài.
Thêm cơ chế đăng ký theo chủ đề: subscribe(topic, observer) với topic là "temperature", "humidity", "aqi". Trạm chỉ báo observer của chủ đề vừa đổi.
indoor.set(24,...), outdoor.set(31,...) -> "Ngoài nóng hơn trong 7.0C"
đổi mỗi humidity -> observer chỉ đăng ký "temperature" không nhận tin
✅ Tiêu chí hoàn thành
- Test mẫu Bài 1 pass: đếm đúng số lần
updateđược gọi. - Bài 2: 3 display cũ không đổi.
- Bài 3 phân biệt đúng 2 nguồn và lọc đúng theo chủ đề.
- Lập bảng đẩy và kéo với số liệu thật từ code của mình (số lần gọi getter, số byte thừa).
❓ Câu hỏi ôn tập
- Đẩy khác kéo ở điểm nào?
- Khi nào nên dùng kéo?
- Cờ đã đổi để làm gì?
- Hàng dựng sẵn có nhược điểm gì?
🌕 Bạn đã hoàn thành ngày 15. Làm hết bài tập phía trên rồi sang ngày tiếp theo.