观察者模式详解:概念、实现与应用
引言
观察者模式是一种行为设计模式,它允许你定义一种订阅机制,可在对象事件发生时通知多个"观察"该对象的其他对象。观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
什么是观察者模式?
观察者模式是一种行为设计模式,它允许你定义一种订阅机制,可在对象事件发生时通知多个"观察"该对象的其他对象。观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
核心思想
观察者模式的核心思想是:
- 发布-订阅机制:定义了发布者和订阅者之间的松耦合关系
- 一对多依赖:一个发布者可以被多个观察者订阅
- 自动通知:当发布者状态改变时,自动通知所有订阅者
为什么需要观察者模式?
在许多情况下,我们需要实现对象之间的松耦合通信:
1. 状态变化通知
当对象状态发生变化时需要通知其他对象:
- 用户界面需要响应数据变化
- 系统组件需要响应配置变化
- 业务逻辑需要响应事件发生
2. 松耦合设计
当需要降低对象之间的耦合度时:
- 发布者不需要知道观察者的具体实现
- 观察者可以动态添加和移除
- 支持运行时的灵活配置
3. 事件驱动系统
当需要构建事件驱动的系统时:
- 支持事件的发布和订阅
- 实现异步事件处理
- 提供可扩展的事件机制
观察者模式的基本实现
让我们从一个简单的观察者模式实现开始:
javascript
// 观察者接口
class Observer {
update(subject) {
throw new Error('必须实现 update 方法');
}
}
// 发布者(主题)
class Subject {
constructor() {
this.observers = [];
}
attach(observer) {
if (!this.observers.includes(observer)) {
this.observers.push(observer);
console.log('发布者: 添加观察者');
}
}
detach(observer) {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
console.log('发布者: 移除观察者');
}
}
notify() {
console.log('发布者: 通知所有观察者');
for (const observer of this.observers) {
observer.update(this);
}
}
}
// 具体发布者
class ConcreteSubject extends Subject {
constructor() {
super();
this.state = 0;
}
getState() {
return this.state;
}
setState(state) {
this.state = state;
console.log(`发布者: 状态改变为 ${state}`);
this.notify();
}
}
// 具体观察者 A
class ConcreteObserverA extends Observer {
update(subject) {
if (subject.getState() < 3) {
console.log('观察者A: 对状态改变做出反应');
}
}
}
// 具体观察者 B
class ConcreteObserverB extends Observer {
update(subject) {
if (subject.getState() >= 3) {
console.log('观察者B: 对状态改变做出反应');
}
}
}
// 客户端代码
function clientCode() {
const subject = new ConcreteSubject();
const observerA = new ConcreteObserverA();
const observerB = new ConcreteObserverB();
subject.attach(observerA);
subject.attach(observerB);
subject.setState(2);
subject.setState(4);
subject.detach(observerA);
subject.setState(5);
}
clientCode();实现要点分析
- 观察者接口:定义观察者的更新接口
- 发布者类:维护观察者列表,提供添加、删除和通知方法
- 具体发布者:实现具体的业务逻辑
- 具体观察者:实现对状态变化的响应逻辑
- 客户端:协调发布者和观察者的关系
观察者模式的实际应用场景
1. 用户界面事件系统
在前端开发中,观察者模式非常适合用于实现事件处理系统:
javascript
// 事件目标接口
class EventTarget {
constructor() {
this.listeners = {};
}
addEventListener(eventType, listener) {
if (!this.listeners[eventType]) {
this.listeners[eventType] = [];
}
if (!this.listeners[eventType].includes(listener)) {
this.listeners[eventType].push(listener);
console.log(`事件系统: 添加 ${eventType} 事件监听器`);
}
}
removeEventListener(eventType, listener) {
if (!this.listeners[eventType]) return;
const index = this.listeners[eventType].indexOf(listener);
if (index !== -1) {
this.listeners[eventType].splice(index, 1);
console.log(`事件系统: 移除 ${eventType} 事件监听器`);
}
}
dispatchEvent(event) {
console.log(`事件系统: 触发 ${event.type} 事件`);
if (this.listeners[event.type]) {
for (const listener of this.listeners[event.type]) {
try {
listener.call(this, event);
} catch (error) {
console.error('事件监听器执行出错:', error);
}
}
}
// 检查是否有对应的 onEvent 方法
const handlerName = `on${event.type.charAt(0).toUpperCase() + event.type.slice(1)}`;
if (typeof this[handlerName] === 'function') {
try {
this[handlerName](event);
} catch (error) {
console.error(`${handlerName} 执行出错:`, error);
}
}
}
}
// 事件对象
class Event {
constructor(type, data = {}) {
this.type = type;
this.data = data;
this.timestamp = Date.now();
this.cancelable = false;
this.defaultPrevented = false;
}
preventDefault() {
if (this.cancelable) {
this.defaultPrevented = true;
}
}
}
// 自定义事件
class CustomEvent extends Event {
constructor(type, data = {}) {
super(type, data);
this.detail = data.detail || null;
}
}
// UI 组件基类
class UIComponent extends EventTarget {
constructor(elementId) {
super();
this.elementId = elementId;
this.visible = true;
this.enabled = true;
}
show() {
if (!this.visible) {
this.visible = true;
this.dispatchEvent(new CustomEvent('show', {
detail: { component: this.elementId }
}));
}
}
hide() {
if (this.visible) {
this.visible = false;
this.dispatchEvent(new CustomEvent('hide', {
detail: { component: this.elementId }
}));
}
}
enable() {
if (!this.enabled) {
this.enabled = true;
this.dispatchEvent(new CustomEvent('enable', {
detail: { component: this.elementId }
}));
}
}
disable() {
if (this.enabled) {
this.enabled = false;
this.dispatchEvent(new CustomEvent('disable', {
detail: { component: this.elementId }
}));
}
}
}
// 按钮组件
class Button extends UIComponent {
constructor(elementId, text) {
super(elementId);
this.text = text;
this.clickCount = 0;
}
click() {
if (this.enabled) {
this.clickCount++;
const event = new CustomEvent('click', {
detail: {
component: this.elementId,
clickCount: this.clickCount,
text: this.text
}
});
event.cancelable = true;
this.dispatchEvent(event);
if (!event.defaultPrevented) {
console.log(`按钮 ${this.elementId} 被点击,这是第 ${this.clickCount} 次点击`);
}
}
}
onClick(event) {
console.log(`按钮 ${this.elementId} 的 onClick 处理器被调用`);
}
}
// 表单组件
class Form extends UIComponent {
constructor(elementId) {
super(elementId);
this.fields = {};
this.isValid = false;
}
addField(fieldName, value = '') {
this.fields[fieldName] = value;
this.dispatchEvent(new CustomEvent('fieldAdded', {
detail: { fieldName, value }
}));
}
updateField(fieldName, value) {
if (this.fields.hasOwnProperty(fieldName)) {
const oldValue = this.fields[fieldName];
this.fields[fieldName] = value;
this.dispatchEvent(new CustomEvent('fieldChanged', {
detail: { fieldName, oldValue, newValue: value }
}));
// 验证表单
this.validate();
}
}
validate() {
const oldValid = this.isValid;
this.isValid = Object.values(this.fields).every(value => value.trim() !== '');
if (oldValid !== this.isValid) {
this.dispatchEvent(new CustomEvent('validationChanged', {
detail: { isValid: this.isValid }
}));
}
}
submit() {
if (this.isValid && this.enabled) {
const event = new CustomEvent('submit', {
detail: { fields: { ...this.fields } }
});
event.cancelable = true;
this.dispatchEvent(event);
if (!event.defaultPrevented) {
console.log('表单提交:', this.fields);
}
}
}
}
// 数据绑定观察者
class DataBindingObserver {
constructor(component, propertyName) {
this.component = component;
this.propertyName = propertyName;
}
update(event) {
console.log(`数据绑定观察者: ${this.component.elementId} 的 ${this.propertyName} 属性更新`);
// 这里可以实现数据绑定逻辑
}
}
// 验证观察者
class ValidationObserver {
constructor(form) {
this.form = form;
this.errorElement = null;
}
update(event) {
if (event.type === 'validationChanged') {
console.log(`验证观察者: 表单验证状态改变为 ${event.detail.isValid}`);
// 更新UI显示验证状态
}
}
}
// 日志观察者
class LoggingObserver {
update(event) {
console.log(`日志观察者: 记录事件 ${event.type}`, event.detail);
}
}
// 使用示例
function uiEventExample() {
console.log('=== UI 事件系统示例 ===');
// 创建 UI 组件
const submitButton = new Button('submitBtn', '提交');
const cancelButton = new Button('cancelBtn', '取消');
const userForm = new Form('userForm');
// 创建观察者
const logger = new LoggingObserver();
const validator = new ValidationObserver(userForm);
// 添加事件监听器
submitButton.addEventListener('click', logger.update.bind(logger));
cancelButton.addEventListener('click', logger.update.bind(logger));
userForm.addEventListener('fieldAdded', logger.update.bind(logger));
userForm.addEventListener('fieldChanged', logger.update.bind(logger));
userForm.addEventListener('validationChanged', validator.update.bind(validator));
userForm.addEventListener('submit', logger.update.bind(logger));
// 模拟用户交互
console.log('\n=== 添加表单字段 ===');
userForm.addField('username', '');
userForm.addField('email', '');
console.log('\n=== 更新表单字段 ===');
userForm.updateField('username', '张三');
userForm.updateField('email', 'zhangsan@example.com');
console.log('\n=== 点击按钮 ===');
submitButton.click();
cancelButton.click();
console.log('\n=== 提交表单 ===');
userForm.submit();
console.log('\n=== 移除监听器并再次操作 ===');
userForm.removeEventListener('fieldChanged', logger.update.bind(logger));
userForm.updateField('username', '李四');
userForm.submit();
}
uiEventExample();2. 股票价格监控系统
在金融系统中,观察者模式非常适合用于实现价格监控和通知:
javascript
// 股票观察者接口
class StockObserver {
update(stockSymbol, price, change) {
throw new Error('必须实现 update 方法');
}
}
// 股票主题接口
class StockSubject {
constructor() {
this.observers = [];
}
attach(observer) {
if (!this.observers.includes(observer)) {
this.observers.push(observer);
console.log('股票系统: 添加观察者');
}
}
detach(observer) {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
console.log('股票系统: 移除观察者');
}
}
notify(symbol, price, change) {
console.log(`股票系统: 通知观察者 ${symbol} 价格变化`);
for (const observer of this.observers) {
observer.update(symbol, price, change);
}
}
}
// 股票数据
class Stock {
constructor(symbol, name, initialPrice) {
this.symbol = symbol;
this.name = name;
this.price = initialPrice;
this.history = [initialPrice];
}
updatePrice(newPrice) {
const change = newPrice - this.price;
this.price = newPrice;
this.history.push(newPrice);
if (this.history.length > 100) {
this.history.shift(); // 保持历史记录在100条以内
}
return change;
}
getPrice() {
return this.price;
}
getSymbol() {
return this.symbol;
}
getName() {
return this.name;
}
getHistory() {
return [...this.history];
}
}
// 股票市场
class StockMarket extends StockSubject {
constructor() {
super();
this.stocks = new Map();
}
addStock(stock) {
this.stocks.set(stock.getSymbol(), stock);
console.log(`股票市场: 添加股票 ${stock.getSymbol()}`);
}
updateStockPrice(symbol, newPrice) {
const stock = this.stocks.get(symbol);
if (stock) {
const change = stock.updatePrice(newPrice);
this.notify(symbol, stock.getPrice(), change);
return true;
}
return false;
}
getStock(symbol) {
return this.stocks.get(symbol);
}
getAllStocks() {
return Array.from(this.stocks.values());
}
}
// 具体观察者:价格警报
class PriceAlertObserver extends StockObserver {
constructor(alertPrice, alertType) {
super();
this.alertPrice = alertPrice;
this.alertType = alertType; // 'above' 或 'below'
}
update(stockSymbol, price, change) {
if (this.alertType === 'above' && price >= this.alertPrice) {
console.log(`🚨 价格警报: ${stockSymbol} 价格 $${price} 超过警戒线 $${this.alertPrice}`);
} else if (this.alertType === 'below' && price <= this.alertPrice) {
console.log(`🚨 价格警报: ${stockSymbol} 价格 $${price} 低于警戒线 $${this.alertPrice}`);
}
}
}
// 具体观察者:交易员
class TraderObserver extends StockObserver {
constructor(name, strategy) {
super();
this.name = name;
this.strategy = strategy;
this.portfolio = {};
}
update(stockSymbol, price, change) {
console.log(`💼 交易员 ${this.name}: 监控到 ${stockSymbol} 价格变动 $${change.toFixed(2)} 至 $${price}`);
// 根据策略决定是否交易
if (this.shouldBuy(stockSymbol, price, change)) {
this.buy(stockSymbol, price);
} else if (this.shouldSell(stockSymbol, price, change)) {
this.sell(stockSymbol, price);
}
}
shouldBuy(stockSymbol, price, change) {
// 简单策略:价格下跌时买入
return change < 0 && Math.abs(change) > 1;
}
shouldSell(stockSymbol, price, change) {
// 简单策略:价格上涨时卖出
return change > 0 && change > 1;
}
buy(stockSymbol, price) {
if (!this.portfolio[stockSymbol]) {
this.portfolio[stockSymbol] = 0;
}
this.portfolio[stockSymbol] += 10; // 简单买入10股
console.log(`📈 交易员 ${this.name}: 买入 10 股 ${stockSymbol} @ $${price}`);
}
sell(stockSymbol, price) {
if (this.portfolio[stockSymbol] && this.portfolio[stockSymbol] >= 10) {
this.portfolio[stockSymbol] -= 10; // 卖出10股
console.log(`📉 交易员 ${this.name}: 卖出 10 股 ${stockSymbol} @ $${price}`);
}
}
}
// 具体观察者:数据分析器
class DataAnalyzerObserver extends StockObserver {
constructor() {
super();
this.dataPoints = new Map();
}
update(stockSymbol, price, change) {
if (!this.dataPoints.has(stockSymbol)) {
this.dataPoints.set(stockSymbol, {
prices: [],
changes: [],
totalChange: 0
});
}
const data = this.dataPoints.get(stockSymbol);
data.prices.push(price);
data.changes.push(change);
data.totalChange += change;
// 保持数据点在合理范围内
if (data.prices.length > 50) {
data.prices.shift();
data.changes.shift();
}
// 分析数据
this.analyze(stockSymbol, data);
}
analyze(stockSymbol, data) {
const avgChange = data.totalChange / data.changes.length;
const volatility = this.calculateVolatility(data.changes);
if (Math.abs(avgChange) > 2) {
console.log(`📊 数据分析: ${stockSymbol} 平均变化 $${avgChange.toFixed(2)}, 波动性 ${volatility.toFixed(2)}`);
}
}
calculateVolatility(changes) {
const mean = changes.reduce((sum, change) => sum + change, 0) / changes.length;
const squareDiffs = changes.map(change => Math.pow(change - mean, 2));
const avgSquareDiff = squareDiffs.reduce((sum, squareDiff) => sum + squareDiff, 0) / squareDiffs.length;
return Math.sqrt(avgSquareDiff);
}
}
// 具体观察者:新闻生成器
class NewsGeneratorObserver extends StockObserver {
constructor() {
super();
this.newsThreshold = 5; // 价格变化超过5%时生成新闻
}
update(stockSymbol, price, change) {
const stock = globalMarket.getStock(stockSymbol);
if (stock) {
const percentChange = (change / (price - change)) * 100;
if (Math.abs(percentChange) >= this.newsThreshold) {
this.generateNews(stockSymbol, stock.getName(), price, change, percentChange);
}
}
}
generateNews(stockSymbol, stockName, price, change, percentChange) {
const direction = change > 0 ? '上涨' : '下跌';
const headline = `${stockName} (${stockSymbol}) 股价大幅${direction} ${Math.abs(percentChange).toFixed(2)}%`;
const content = `${stockName} 股票价格今日${direction}至 $${price},单日波动达到 ${Math.abs(percentChange).toFixed(2)}%,市场分析人士对此表示关注。`;
console.log(`📰 新闻: ${headline}`);
console.log(` ${content}`);
}
}
// 全局股票市场实例
let globalMarket;
// 使用示例
function stockMarketExample() {
console.log('=== 股票市场监控系统 ===');
// 创建股票市场
globalMarket = new StockMarket();
// 添加股票
const appleStock = new Stock('AAPL', 'Apple Inc.', 150.00);
const googleStock = new Stock('GOOGL', 'Alphabet Inc.', 2800.00);
const teslaStock = new Stock('TSLA', 'Tesla Inc.', 800.00);
globalMarket.addStock(appleStock);
globalMarket.addStock(googleStock);
globalMarket.addStock(teslaStock);
// 创建观察者
const priceAlert1 = new PriceAlertObserver(160, 'above');
const priceAlert2 = new PriceAlertObserver(750, 'below');
const trader1 = new TraderObserver('张三', 'aggressive');
const trader2 = new TraderObserver('李四', 'conservative');
const analyzer = new DataAnalyzerObserver();
const newsGenerator = new NewsGeneratorObserver();
// 订阅股票价格变化
globalMarket.attach(priceAlert1);
globalMarket.attach(priceAlert2);
globalMarket.attach(trader1);
globalMarket.attach(trader2);
globalMarket.attach(analyzer);
globalMarket.attach(newsGenerator);
console.log('\n=== 模拟股票价格变化 ===');
// 模拟价格变化
const priceChanges = [
{ symbol: 'AAPL', prices: [152, 155, 158, 162, 159, 165] },
{ symbol: 'GOOGL', prices: [2810, 2820, 2815, 2830, 2850, 2840] },
{ symbol: 'TSLA', prices: [810, 820, 790, 760, 740, 780] }
];
for (let day = 0; day < 6; day++) {
console.log(`\n--- 第 ${day + 1} 天 ---`);
for (const stockChange of priceChanges) {
const newPrice = stockChange.prices[day];
globalMarket.updateStockPrice(stockChange.symbol, newPrice);
}
}
console.log('\n=== 移除部分观察者 ===');
globalMarket.detach(priceAlert1);
globalMarket.detach(trader2);
console.log('\n=== 继续价格变化 ===');
globalMarket.updateStockPrice('AAPL', 170);
globalMarket.updateStockPrice('TSLA', 800);
}
// 运行示例
stockMarketExample();3. 配置管理系统
在应用配置管理中,观察者模式非常适合用于实现配置变更通知:
javascript
// 配置观察者接口
class ConfigObserver {
update(configKey, oldValue, newValue) {
throw new Error('必须实现 update 方法');
}
}
// 配置主题
class ConfigSubject {
constructor() {
this.observers = [];
}
subscribe(observer) {
if (!this.observers.includes(observer)) {
this.observers.push(observer);
console.log('配置系统: 添加配置观察者');
}
}
unsubscribe(observer) {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
console.log('配置系统: 移除配置观察者');
}
}
notify(configKey, oldValue, newValue) {
console.log(`配置系统: 通知观察者配置 ${configKey} 发生变化`);
for (const observer of this.observers) {
observer.update(configKey, oldValue, newValue);
}
}
}
// 配置管理器
class ConfigManager extends ConfigSubject {
constructor() {
super();
this.config = new Map();
this.history = new Map();
}
set(key, value) {
const oldValue = this.config.get(key);
this.config.set(key, value);
// 记录历史
if (!this.history.has(key)) {
this.history.set(key, []);
}
this.history.get(key).push({
value: value,
timestamp: Date.now(),
oldValue: oldValue
});
// 限制历史记录数量
const history = this.history.get(key);
if (history.length > 100) {
history.shift();
}
console.log(`配置管理器: 设置配置 ${key} = ${JSON.stringify(value)}`);
// 通知观察者
if (oldValue !== value) {
this.notify(key, oldValue, value);
}
}
get(key, defaultValue = null) {
return this.config.has(key) ? this.config.get(key) : defaultValue;
}
has(key) {
return this.config.has(key);
}
delete(key) {
if (this.config.has(key)) {
const oldValue = this.config.get(key);
this.config.delete(key);
this.notify(key, oldValue, undefined);
return true;
}
return false;
}
getAll() {
return Object.fromEntries(this.config);
}
getHistory(key) {
return this.history.has(key) ? [...this.history.get(key)] : [];
}
load(configObject) {
console.log('配置管理器: 批量加载配置');
for (const [key, value] of Object.entries(configObject)) {
this.set(key, value);
}
}
reset() {
const oldConfig = this.getAll();
this.config.clear();
this.history.clear();
// 通知所有配置被重置
for (const [key, oldValue] of Object.entries(oldConfig)) {
this.notify(key, oldValue, undefined);
}
console.log('配置管理器: 配置已重置');
}
}
// 具体观察者:日志记录器
class ConfigLoggerObserver extends ConfigObserver {
update(configKey, oldValue, newValue) {
const timestamp = new Date().toISOString();
if (newValue === undefined) {
console.log(`[${timestamp}] 配置日志: 配置项 ${configKey} 已删除 (旧值: ${JSON.stringify(oldValue)})`);
} else if (oldValue === undefined) {
console.log(`[${timestamp}] 配置日志: 配置项 ${configKey} 已添加 (新值: ${JSON.stringify(newValue)})`);
} else {
console.log(`[${timestamp}] 配置日志: 配置项 ${configKey} 已更新 (旧值: ${JSON.stringify(oldValue)}, 新值: ${JSON.stringify(newValue)})`);
}
}
}
// 具体观察者:验证器
class ConfigValidatorObserver extends ConfigObserver {
constructor(validationRules) {
super();
this.validationRules = validationRules || {};
}
update(configKey, oldValue, newValue) {
if (newValue !== undefined && this.validationRules[configKey]) {
const validator = this.validationRules[configKey];
const isValid = validator(newValue);
if (!isValid) {
console.error(`❌ 配置验证: 配置项 ${configKey} 的值 ${JSON.stringify(newValue)} 无效`);
// 可以选择恢复旧值或抛出异常
} else {
console.log(`✅ 配置验证: 配置项 ${configKey} 的值有效`);
}
}
}
}
// 具体观察者:缓存管理器
class CacheManagerObserver extends ConfigObserver {
constructor(cache) {
super();
this.cache = cache;
this.cacheInvalidationRules = {};
}
addInvalidationRule(configKey, cacheKeys) {
this.cacheInvalidationRules[configKey] = cacheKeys;
}
update(configKey, oldValue, newValue) {
if (this.cacheInvalidationRules[configKey]) {
const cacheKeys = this.cacheInvalidationRules[configKey];
for (const cacheKey of cacheKeys) {
if (this.cache.has(cacheKey)) {
this.cache.delete(cacheKey);
console.log(`キャッシング管理: 由于配置 ${configKey} 变更,已清除缓存 ${cacheKey}`);
}
}
}
}
}
// 具体观察者:功能开关
class FeatureToggleObserver extends ConfigObserver {
constructor(features) {
super();
this.features = features || {};
}
update(configKey, oldValue, newValue) {
if (configKey.startsWith('feature.')) {
const featureName = configKey.substring(8); // 移除 'feature.' 前缀
const isEnabled = Boolean(newValue);
if (this.features[featureName]) {
this.features[featureName].enabled = isEnabled;
console.log(`功能开关: 功能 ${featureName} ${isEnabled ? '启用' : '禁用'}`);
}
}
}
isFeatureEnabled(featureName) {
return this.features[featureName] && this.features[featureName].enabled;
}
}
// 具体观察者:性能监控
class PerformanceMonitorObserver extends ConfigObserver {
constructor() {
super();
this.configChangeCount = 0;
this.lastChangeTime = Date.now();
}
update(configKey, oldValue, newValue) {
this.configChangeCount++;
const now = Date.now();
const timeSinceLastChange = now - this.lastChangeTime;
this.lastChangeTime = now;
console.log(`📊 性能监控: 配置变更计数 ${this.configChangeCount}, 距离上次变更 ${timeSinceLastChange}ms`);
}
getStats() {
return {
configChangeCount: this.configChangeCount,
timeSinceLastChange: Date.now() - this.lastChangeTime
};
}
}
// 使用示例
function configManagementExample() {
console.log('=== 配置管理系统示例 ===');
// 创建配置管理器
const configManager = new ConfigManager();
// 创建观察者
const logger = new ConfigLoggerObserver();
// 验证规则
const validationRules = {
'server.port': (value) => Number.isInteger(value) && value > 0 && value < 65536,
'database.url': (value) => typeof value === 'string' && value.startsWith('mongodb://'),
'cache.enabled': (value) => typeof value === 'boolean',
'log.level': (value) => ['debug', 'info', 'warn', 'error'].includes(value)
};
const validator = new ConfigValidatorObserver(validationRules);
// 缓存管理
const cache = new Map();
const cacheManager = new CacheManagerObserver(cache);
cacheManager.addInvalidationRule('cache.enabled', ['userCache', 'productCache']);
cacheManager.addInvalidationRule('database.url', ['dbConnectionCache']);
// 功能开关
const features = {
'newUI': { enabled: false, description: '新用户界面' },
'betaFeature': { enabled: false, description: '测试功能' }
};
const featureToggle = new FeatureToggleObserver(features);
// 性能监控
const performanceMonitor = new PerformanceMonitorObserver();
// 订阅配置变化
configManager.subscribe(logger);
configManager.subscribe(validator);
configManager.subscribe(cacheManager);
configManager.subscribe(featureToggle);
configManager.subscribe(performanceMonitor);
console.log('\n=== 加载初始配置 ===');
const initialConfig = {
'server.port': 3000,
'database.url': 'mongodb://localhost:27017/myapp',
'cache.enabled': true,
'log.level': 'info',
'feature.newUI': false,
'feature.betaFeature': false
};
configManager.load(initialConfig);
console.log('\n=== 修改配置 ===');
configManager.set('server.port', 4000);
configManager.set('cache.enabled', false);
configManager.set('log.level', 'debug');
configManager.set('feature.newUI', true);
console.log('\n=== 测试无效配置 ===');
configManager.set('server.port', 99999); // 无效端口
configManager.set('database.url', 'invalid-url'); // 无效URL
console.log('\n=== 添加缓存并测试清除 ===');
cache.set('userCache', '用户数据缓存');
cache.set('productCache', '产品数据缓存');
console.log(`缓存状态: userCache=${cache.has('userCache')}, productCache=${cache.has('productCache')}`);
// 更改缓存配置,触发缓存清除
configManager.set('cache.enabled', true);
console.log(`缓存状态: userCache=${cache.has('userCache')}, productCache=${cache.has('productCache')}`);
console.log('\n=== 检查功能开关 ===');
console.log(`新UI功能是否启用: ${featureToggle.isFeatureEnabled('newUI')}`);
console.log(`测试功能是否启用: ${featureToggle.isFeatureEnabled('betaFeature')}`);
console.log('\n=== 性能监控统计 ===');
console.log('监控统计:', performanceMonitor.getStats());
console.log('\n=== 配置历史 ===');
console.log('端口配置历史:', configManager.getHistory('server.port'));
}
// 运行示例
configManagementExample();观察者模式的实现要点
1. 推模型 vs 拉模型
javascript
// 推模型 - 发布者主动推送详细信息
class PushObserver {
update(subject, data) {
// 发布者推送具体数据
}
}
// 拉模型 - 观察者主动获取所需信息
class PullObserver {
update(subject) {
// 观察者从发布者拉取数据
const data = subject.getData();
}
}2. 通知顺序
javascript
class Subject {
notify() {
// 可以按特定顺序通知观察者
for (const observer of this.observers) {
observer.update(this);
}
// 或者按优先级通知
// this.observers.sort((a, b) => a.priority - b.priority);
}
}3. 异常处理
javascript
class RobustSubject {
notify() {
for (const observer of this.observers) {
try {
observer.update(this);
} catch (error) {
console.error('观察者通知失败:', error);
// 可以选择移除失败的观察者
}
}
}
}观察者模式与其它模式的对比
观察者模式 vs 发布-订阅模式
javascript
// 观察者模式 - 直接依赖
class Subject {
notify() {
// 直接调用观察者方法
for (const observer of this.observers) {
observer.update(this);
}
}
}
// 发布-订阅模式 - 通过中介
class EventBus {
publish(event, data) {
// 通过事件总线间接通知
this.subscribers.forEach(subscriber => {
if (subscriber.event === event) {
subscriber.callback(data);
}
});
}
}观察者模式 vs 状态模式
javascript
// 观察者模式 - 一对多依赖
class Observer {
update(subject) {
// 响应主题状态变化
}
}
// 状态模式 - 对象内部状态变化
class State {
handle(context) {
// 处理特定状态的行为
context.changeState(new AnotherState());
}
}观察者模式的优缺点
优点
- 松耦合:发布者和观察者之间松耦合
- 动态关系:可以动态添加和移除观察者
- 广播通信:支持一对多的通信方式
- 符合开闭原则:增加新的观察者无需修改发布者代码
缺点
- 内存泄漏:忘记移除观察者可能导致内存泄漏
- 性能问题:大量观察者时通知可能影响性能
- 调试困难:复杂的观察者链路难以调试
- 意外更新:观察者可能被意外通知
总结
观察者模式是一种行为设计模式,它允许你定义一种订阅机制,可在对象事件发生时通知多个"观察"该对象的其他对象。观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
通过本章的学习,我们了解了:
- 观察者模式的基本概念和核心思想
- 观察者模式的实现方式和关键要点
- 观察者模式在实际开发中的应用场景(UI事件系统、股票监控、配置管理)
- 观察者模式与其他行为型模式的对比
- 观察者模式的优缺点
观察者模式在现代软件开发中应用广泛,特别是在需要实现对象间松耦合通信、构建事件驱动系统、处理状态变化通知的场景中,它可以很好地支持系统的灵活性和可维护性。
在下一章中,我们将继续探讨其他行为型模式,首先是策略模式。