Observer nâng cao: pull vs push và trạm thời tiết

So sánh mô hình đẩy và kéo dữ liệu, bài toán bảng chỉ cần một phần số đo, và Observer có sẵn trong thư viện.
Trung bìnhDesign pattern ~60 phút

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íĐẩyKéo
Số bước1 bước nhận đủ2 bước báo rồi lấy
Nhận thừaHay thừaChỉ lấy phần cần
Thêm chỉ số mớiNhiều bảng phải sửaBả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ầuChi tiết
Chỉ báo tin ngắnupdate(*this), observer tự gọi getter cần thiết
Cờ changedsetChanged() 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.

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.