观察者模式
本课属于 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 方法。观察者可以随时订阅或取消订阅,这让系统更加灵活,耦合度也更低。主题不需要知道观察者的具体类型。
挑战
简单让我们使用观察者模式构建一个股票价格提醒系统!你将创建一个系统,当股票行情器的价格发生变化时,它会通知多位投资者,让每位投资者都能以自己的方式响应市场动态。
你将把代码组织到两个文件中:
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 应收到通知)
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器