Skip to content

观察者模式详解:概念、实现与应用

引言

观察者模式是一种行为设计模式,它允许你定义一种订阅机制,可在对象事件发生时通知多个"观察"该对象的其他对象。观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。

什么是观察者模式?

观察者模式是一种行为设计模式,它允许你定义一种订阅机制,可在对象事件发生时通知多个"观察"该对象的其他对象。观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。

核心思想

观察者模式的核心思想是:

  1. 发布-订阅机制:定义了发布者和订阅者之间的松耦合关系
  2. 一对多依赖:一个发布者可以被多个观察者订阅
  3. 自动通知:当发布者状态改变时,自动通知所有订阅者

为什么需要观察者模式?

在许多情况下,我们需要实现对象之间的松耦合通信:

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. 观察者接口:定义观察者的更新接口
  2. 发布者类:维护观察者列表,提供添加、删除和通知方法
  3. 具体发布者:实现具体的业务逻辑
  4. 具体观察者:实现对状态变化的响应逻辑
  5. 客户端:协调发布者和观察者的关系

观察者模式的实际应用场景

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());
  }
}

观察者模式的优缺点

优点

  1. 松耦合:发布者和观察者之间松耦合
  2. 动态关系:可以动态添加和移除观察者
  3. 广播通信:支持一对多的通信方式
  4. 符合开闭原则:增加新的观察者无需修改发布者代码

缺点

  1. 内存泄漏:忘记移除观察者可能导致内存泄漏
  2. 性能问题:大量观察者时通知可能影响性能
  3. 调试困难:复杂的观察者链路难以调试
  4. 意外更新:观察者可能被意外通知

总结

观察者模式是一种行为设计模式,它允许你定义一种订阅机制,可在对象事件发生时通知多个"观察"该对象的其他对象。观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。

通过本章的学习,我们了解了:

  1. 观察者模式的基本概念和核心思想
  2. 观察者模式的实现方式和关键要点
  3. 观察者模式在实际开发中的应用场景(UI事件系统、股票监控、配置管理)
  4. 观察者模式与其他行为型模式的对比
  5. 观察者模式的优缺点

观察者模式在现代软件开发中应用广泛,特别是在需要实现对象间松耦合通信、构建事件驱动系统、处理状态变化通知的场景中,它可以很好地支持系统的灵活性和可维护性。

在下一章中,我们将继续探讨其他行为型模式,首先是策略模式。