Menu
CoddyTech

Mẫu Observer

Thuộc phần Lập trình hướng đối tượng trong hành trình Dart của Coddy. Bài học 92 trên 110.

Mẫu thiết kế Observer thiết lập mối quan hệ một-nhiều giữa các đối tượng: khi một đối tượng (đối tượng chủ thể) thay đổi trạng thái, tất cả các đối tượng phụ thuộc vào nó (đối tượng quan sát) sẽ tự động nhận được thông báo. Mẫu này rất phù hợp với các tình huống như cập nhật giao diện người dùng, hệ thống sự kiện hoặc bất kỳ tình huống nào mà nhiều phần trong ứng dụng cần phản ứng với các thay đổi.

Mẫu này có hai vai trò chính: Chủ thể duy trì danh sách các trình quan sát và thông báo cho họ khi có thay đổi, còn Trình quan sát tự đăng ký và phản hồi các cập nhật:

abstract class Observer {
  void update(String message);
}

class NewsAgency {
  final List<Observer> _observers = [];
  String _latestNews = '';

  void subscribe(Observer observer) {
    _observers.add(observer);
  }

  void unsubscribe(Observer observer) {
    _observers.remove(observer);
  }

  void publishNews(String news) {
    _latestNews = news;
    for (var observer in _observers) {
      observer.update(_latestNews);
    }
  }
}

class NewsChannel implements Observer {
  final String name;
  NewsChannel(this.name);

  @override
  void update(String message) {
    print('$name received: $message');
  }
}

void main() {
  var agency = NewsAgency();
  var cnn = NewsChannel('CNN');
  var bbc = NewsChannel('BBC');

  agency.subscribe(cnn);
  agency.subscribe(bbc);

  agency.publishNews('Breaking news!');
  // CNN đã nhận: Tin nóng!
  // BBC đã nhận: Tin nóng!
}

Khi gọi publishNews, cơ quan lần lượt duyệt qua tất cả các observer đã đăng ký và gọi phương thức update của họ. Observer có thể đăng ký hoặc hủy đăng ký bất cứ lúc nào, giúp hệ thống linh hoạt và ít phụ thuộc lẫn nhau: đối tượng chủ thể không cần biết kiểu cụ thể của các observer.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống cảnh báo giá cổ phiếu bằng mẫu Observer! Bạn sẽ tạo một hệ thống trong đó mã theo dõi cổ phiếu thông báo cho nhiều nhà đầu tư mỗi khi giá thay đổi, để mỗi nhà đầu tư có thể phản ứng theo cách riêng trước những cập nhật của thị trường.

Bạn sẽ sắp xếp code thành hai tệp:

  • stock_system.dart: Tạo hệ thống observer tại đây:
    • Một lớp trừu tượng Investor có phương thức void onPriceChange(String stockName, double price)
    • Một lớp DayTrader triển khai Investor. Lớp này có trường name và phương thức onPriceChange in ra: [name] sees [stockName] at $[price] - Making quick trade!
    • Một lớp LongTermInvestor triển khai Investor. Lớp này có trường name và phương thức onPriceChange in ra: [name] notes [stockName] at $[price] - Holding steady.
    • Một lớp StockTicker (đối tượng phát thông báo) có:
      • Một trường String stockName
      • Một danh sách riêng để lưu các nhà đầu tư đã đăng ký
      • Một phương thức subscribe(Investor investor) để thêm nhà đầu tư
      • Một phương thức unsubscribe(Investor investor) để xóa nhà đầu tư
      • Một phương thức updatePrice(double newPrice) thông báo giá mới cho tất cả nhà đầu tư đã đăng ký
  • main.dart: Nhập hệ thống cổ phiếu của bạn và minh họa cách mẫu Observer hoạt động:
    • Tạo một StockTicker cho cổ phiếu có tên DART
    • Tạo một DayTrader tên Alice và một LongTermInvestor tên Bob
    • Đăng ký cả hai nhà đầu tư với mã theo dõi
    • Cập nhật giá thành 150.50 (cả hai nhà đầu tư đều nhận được thông báo)
    • In ra một dòng trống
    • Hủy đăng ký Alice khỏi mã theo dõi
    • Cập nhật giá thành 155.75 (lúc này chỉ Bob nhận được thông báo)

Ví dụ này cho thấy mẫu Observer tạo ra một hệ thống ít phụ thuộc lẫn nhau. StockTicker không cần biết mình đang thông báo cho nhà giao dịch trong ngày hay nhà đầu tư dài hạn, mà chỉ cần gọi onPriceChange cho những người đã đăng ký!

Đầu ra dự kiến:

Alice sees DART at $150.5 - Making quick trade!
Bob notes DART at $150.5 - Holding steady.

Bob notes DART at $155.75 - Holding steady.

Tự làm thử

import 'stock_system.dart';

void main() {
  // TODO: Tạo một StockTicker cho cổ phiếu tên 'DART'
  
  // TODO: Tạo một DayTrader tên 'Alice'
  
  // TODO: Tạo một LongTermInvestor tên 'Bob'
  
  // TODO: Đăng ký cả hai nhà đầu tư theo dõi ticker
  
  // TODO: Cập nhật giá thành 150.50 (cả hai nhà đầu tư đều phải nhận thông báo)
  
  // TODO: In ra một dòng trống
  
  // TODO: Hủy đăng ký theo dõi ticker cho Alice
  
  // TODO: Cập nhật giá thành 155.75 (giờ chỉ Bob nhận thông báo)
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Dart online