用ts实现观察者模式,附上关注主播,主播上线通知粉丝例子

220 阅读2分钟

概述

观察者模式是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。

问题

假如你有两种类型的对象: 顾客和 商店 。 顾客对某个特定品牌的产品非常感兴趣 (例如最新型号的 iPhone 手机), 而该产品很快将会在商店里出售。

顾客可以每天来商店看看产品是否到货。 但如果商品尚未到货时, 绝大多数来到商店的顾客都会空手而归。

解决方案

拥有一些值得关注的状态的对象通常被称为目标, 由于它要将自身的状态改变通知给其他对象, 我们也将其称为发布者 (publisher)。 所有希望关注发布者状态变化的其他对象被称为订阅者 (subscribers)。

观察者模式建议你为发布者类添加订阅机制, 让每个对象都能订阅或取消订阅发布者事件流。 不要害怕! 这并不像听上去那么复杂。 实际上, 该机制包括 1) 一个用于存储订阅者对象引用的列表成员变量; 2) 几个用于添加或删除该列表中订阅者的公有方法。

TS代码实现

/*  观察者模式 */

/**
 * 发布者
 */
 interface Subject {
    // 订阅
    attach(observer: Observer): void;

    // 取消订阅
    detach(observer: Observer): void;

    // 通知
    notify(): void;
}

/**
 * 发布者拥有一些重要的状态,并在状态发生变化时通知观察者。
 */
class ConcreteSubject implements Subject {
    /**
     * @type {number} 状态  数据
     */
    public state: number;

    /**
     * @type {Observer[]} 观察者们(订阅者们)
     */
    private observers: Observer[] = [];

    /**
     * 订阅方法
     */
    public attach(observer: Observer): void {
        // 是否存在
        const isExist = this.observers.includes(observer);
        if (isExist) {
            return console.log('发布者:已经订阅啦');
        }

        console.log('发布者:订阅成功');
        this.observers.push(observer);
    }

    public detach(observer: Observer): void {
        const observerIndex = this.observers.indexOf(observer);
        if (observerIndex === -1) {
            return console.log('发布者:没找到该订阅者');
        }

        this.observers.splice(observerIndex, 1);
        console.log('发布者:取消订阅');
    }

    /**
     * 通知
     */
    public notify(): void {
        console.log('发布者:通知观察者们更新');
        for (const observer of this.observers) {
            observer.update(this);
        }
    }

    /**
     * 特定业务逻辑触发通知方法
     */
    public someBusinessLogic(): void {
        console.log('\nSubject: I'm doing something important.');
        this.state = Math.floor(Math.random() * (10 + 1));
        console.log(`Subject: My state has just changed to: ${this.state}`);
        this.notify();
    }
}

/**
 * 观察者
 */
interface Observer {
    // Receive update from subject. 更新
    update(subject: Subject): void;
}

/**
 * 观察者
 */
class ConcreteObserverA implements Observer {
    public update(subject: Subject): void {
        if (subject instanceof ConcreteSubject && subject.state < 3) {
            console.log('状态小于三');
        }
    }
}

class ConcreteObserverB implements Observer {
    public update(subject: Subject): void {
        if (subject instanceof ConcreteSubject && (subject.state === 0 || subject.state >= 2)) {
            console.log('等于0 或大于等于2');
        }
    }
}

/**
 * The client code.
 */

const subject = new ConcreteSubject();

const observer1 = new ConcreteObserverA();
subject.attach(observer1);

const observer2 = new ConcreteObserverB();
subject.attach(observer2);

subject.someBusinessLogic();
subject.someBusinessLogic();

subject.detach(observer2);

subject.someBusinessLogic();

参考文件

refactoringguru.cn/design-patt…

现实生活中的例子

粉丝关注主播,主播开播后通知粉丝开播啦

/*  观察者模式 */

/**
 * 发布者
 */
 interface Subject {
  // 订阅
  attach(observer: Observer): void;

  // 取消订阅
  detach(observer: Observer): void;

  // 通知
  notify(): void;
}

/**
* 主播
*/
class AnchorSubject implements Subject {
  constructor(isOnLine, name) {
    this.isOnLine = isOnLine
    this.name = name
  }
  public isOnLine: boolean; // 主播是否在线
  public name: string; // 主播姓名
  private observers: Observer[] = []; // 粉丝们
  // 关注
  public attach(observer: Observer): void {
      // 是否已经关注
      const isExist = this.observers.includes(observer);
      if (isExist) {
          return console.log(`${this.name}:你已经关注我啦,你双击关注是想取关吗!`);
      }
      console.log(`${this.name}:谢谢关注`);
      this.observers.push(observer);
  }

  // 取关
  public detach(observer: Observer): void {
      const observerIndex = this.observers.indexOf(observer);
      if (observerIndex === -1) {
          return console.log(`${this.name}:先关注我才能取关哦`);
      }
      this.observers.splice(observerIndex, 1);
      console.log(`${this.name}:取关成功,等你回来`);
  }

  /**
   * 通知
   */
  public notify(): void {
    if (this.isOnLine) {
      console.log(`${this.name}:粉丝们我开播了`);
      for (const observer of this.observers) {
          observer.update(this);
      }
    } else {
      console.log(`${this.name}:*** 耻辱下播`);
      for (const observer of this.observers) {
          observer.update(this);
      }
    }
  }

  /**
   * 开播 上线
   */
  public goOnline(): void {
    this.isOnLine = true;
    this.notify();
  }

  /**
   * 耻辱下播 下线
   */
  public offline(): void {
    this.isOnLine = false;
    this.notify();
  }

}

/**
* 观察者
*/
interface Observer {
  update(subject: Subject): void;
}

/**
* 粉丝 
*/
class FansObserverA implements Observer {
  public update(subject: Subject): void {
      if (subject instanceof AnchorSubject && subject.isOnLine) {
          console.log(`${subject.name}:开播啦`);
      } else {
        console.log(`彩笔耻辱下播了`);
      }
  }
}

/**
* The client code.
*/
// 创建一个主播
const subject = new AnchorSubject(false, 'YYF');
// 创建一个粉丝
const fansA = new FansObserverA();
// 关注
subject.attach(fansA);
// 主播上线
subject.goOnline();
// 取关
subject.detach(fansA);
// 关注
subject.attach(fansA);
// 关注
subject.attach(fansA);
// 主播下线
subject.offline();

运行结果

yyfyyds