Menu
CoddyTech

观察者模式

本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 92 课,共 110 课。

观察者模式在对象之间建立一对多关系:当一个对象(主题)状态发生变化时,它的所有依赖对象(观察者)都会自动收到通知。这非常适用于 UI 更新、事件系统等场景,也适用于应用中多个部分都需要对变化作出响应的情况。

这种模式包含两个关键角色:主题负责维护观察者列表,并在发生变化时通知它们;观察者会注册自己,并响应更新:

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 received: Breaking news!
  // BBC received: Breaking news!
}

调用 publishNews 时,代理会遍历所有已订阅的观察者,并调用它们的 update 方法。观察者可以随时订阅或取消订阅,这让系统更加灵活,耦合度也更低。主题不需要知道观察者的具体类型。

challenge icon

挑战

简单

让我们使用观察者模式构建一个股票价格提醒系统!你将创建一个系统,当股票行情器的价格发生变化时,它会通知多位投资者,让每位投资者都能以自己的方式响应市场动态。

你将把代码组织到两个文件中:

  • stock_system.dart:在这里创建观察者系统:
    • 一个抽象类 Investor,包含方法 void onPriceChange(String stockName, double price)
    • 一个实现 Investor 的类 DayTrader。它有一个 name 字段,其 onPriceChange 方法会打印:[name] sees [stockName] at $[price] - Making quick trade!
    • 一个实现 Investor 的类 LongTermInvestor。它有一个 name 字段,其 onPriceChange 方法会打印:[name] notes [stockName] at $[price] - Holding steady.
    • 一个类 StockTicker(主题),包含:
      • 一个 String stockName 字段
      • 一个用于存储已订阅投资者的私有列表
      • 一个用于添加投资者的 subscribe(Investor investor) 方法
      • 一个用于移除投资者的 unsubscribe(Investor investor) 方法
      • 一个 updatePrice(double newPrice) 方法,用于通知所有已订阅的投资者新价格
  • main.dart:导入你的股票系统,并演示观察者模式的实际效果:
    • 为名为 DART 的股票创建一个 StockTicker
    • 创建一个名为 Alice 的 DayTrader,以及一个名为 Bob 的 LongTermInvestor
    • 将两位投资者都订阅到行情器
    • 将价格更新为 150.50(两位投资者都应收到通知)
    • 打印一个空行
    • 取消 Alice 对行情器的订阅
    • 将价格更新为 155.75(现在应该只有 Bob 收到通知)

这展示了观察者模式如何创建松耦合系统:StockTicker 不需要知道它通知的是日内交易者还是长期投资者,只需对所有已订阅者调用 onPriceChange!

预期输出:

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.

亲手试试

import 'stock_system.dart';

void main() {
  // TODO: 为名为 'DART' 的股票创建一个 StockTicker
  
  // TODO: 创建一个名为 'Alice' 的 DayTrader
  
  // TODO: 创建一个名为 'Bob' 的 LongTermInvestor
  
  // TODO: 让两位投资者都订阅该行情器
  
  // TODO: 将价格更新为 150.50(两位投资者都应收到通知)
  
  // TODO: 打印一个空行
  
  // TODO: 取消 Alice 对该行情器的订阅
  
  // TODO: 将价格更新为 155.75(此时只有 Bob 应收到通知)
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Dart 在线编译器