typescript: Observer Pattern

发布时间 2023-10-12 18:23:32作者: ®Geovin Du Dream Park™

 

/**
 * Observer Pattern 观察者是一种行为设计模式, 允许一个对象将其状态的改变通知其他对象
 * file: Observerts.ts
 * The Subject interface declares a set of methods for managing subscribers.
 */
interface GeovinSubject {

    // Attach an observer to the subject.
    attach(observer: Observer):string ; //void

    // Detach an observer from the subject.
    detach(observer: Observer):string ; //void

    // Notify all observers about an event.
    notify(): string; //void
}

/**
 * The Subject owns some important state and notifies observers when the state
 * changes.
 */
class ConcreteSubject implements GeovinSubject {
    /**
     * @type {number} For the sake of simplicity, the Subject's state, essential
     * to all subscribers, is stored in this variable.
     */
    public state: number;

    /**
     * @type {Observer[]} List of subscribers. In real life, the list of
     * subscribers can be stored more comprehensively (categorized by event
     * type, etc.).
     */
    private observers: Observer[] = [];

    /**
     * The subscription management methods.
     */
    public attach(observer: Observer): string { //void
        const isExist = this.observers.includes(observer);  //es2016 later
        if (isExist) {
            // console.log('Subject: Observer has been attached already.');
            return "Subject: Observer has been attached already.";
        }

        console.log('Subject: Attached an observer.');
        this.observers.push(observer);
        return "Subject: Attached an observer.";
    }

    public detach(observer: Observer): string {
        const observerIndex = this.observers.indexOf(observer);
        if (observerIndex === -1) {
            console.log('Subject: Nonexistent observer.');
            return "Subject: Nonexistent observer.";
        }

        this.observers.splice(observerIndex, 1);
        console.log('Subject: Detached an observer.');
        return "Subject: Detached an observer.";
    }

    /**
     * Trigger an update in each subscriber.
     */
    public notify(): string {
        let getstr="";
        console.log('Subject: Notifying observers...');
        for (const observer of this.observers) {
            observer.update(this);
            getstr=getstr+"Subject: Notifying observers...";
        }
        return getstr;
    }

    /**
     * Usually, the subscription logic is only a fraction of what a Subject can
     * really do. Subjects commonly hold some important business logic, that
     * triggers a notification method whenever something important is about to
     * happen (or after it).
     */
    public someBusinessLogic(): string { //void
        let getstr="";
        console.log('\nSubject: I\'m doing something important.');
        this.state = Math.floor(Math.random() * (10 + 1));

        getstr=getstr+this.state.toString();

        console.log(`Subject: My state has just changed to: ${this.state}`);
        getstr=getstr+this.notify();
        return getstr;
    }
}

/**
 * 接口
 * The Observer interface declares the update method, used by subjects.
 */
interface Observer {
    // Receive update from subject.
    update(subject: GeovinSubject): string; //void
}

/**
 * Concrete Observers react to the updates issued by the Subject they had been
 * attached to.
 */
class ConcreteObserverA implements Observer {

    /**
     * 
     * @param subject 
     * @returns 
     */
    public update(subject: GeovinSubject): string { //void
        if (subject instanceof ConcreteSubject && subject.state < 3) {
            console.log('ConcreteObserverA: Reacted to the event.');
            return "ConcreteObserverA: Reacted to the event.";
        }
    }
}

/**
 * 
 */
class ConcreteObserverB implements Observer {

    /**
     * 
     * @param subject 
     * @returns
     */
    public update(subject: GeovinSubject): string { //void

        if (subject instanceof ConcreteSubject && (subject.state === 0 || subject.state >= 2)) {

            console.log('ConcreteObserverB: Reacted to the event.');
            return "ConcreteObserverB: Reacted to the event.";
        }
    }
}
//bing AI 生成的代码示例
// 定义被观察者接口
interface Observable {
    // 添加观察者
    addObserver(observer: DuObserver): void;
    // 删除观察者
    removeObserver(observer: DuObserver): void;
    // 通知所有观察者
    notifyObservers(): void;
  }
  
  // 定义观察者接口
  interface DuObserver {
    // 接收被观察者的通知
    update(observable: Observable): void;
  }
  
  // 定义一个具体的被观察者类:温度计
  class Thermometer implements Observable {
    // 存储观察者列表
    private observers: DuObserver[] = [];
    // 存储温度值
    private temperature: number;
  
    // 添加观察者
    public addObserver(observer: DuObserver): void {
      this.observers.push(observer);
      console.log("添加了一个观察者");
    }
  
    // 删除观察者
    public removeObserver(observer: DuObserver): void {
      const index = this.observers.indexOf(observer);
      if (index > -1) {
        this.observers.splice(index, 1);
        console.log("删除了一个观察者");
      }
    }
  
    // 通知所有观察者
    public notifyObservers(): void {
      for (const observer of this.observers) {
        observer.update(this);
      }
      console.log("通知了所有观察者");
    }
  
    // 获取温度值
    public getTemperature(): number {
      return this.temperature;
    }
  
    // 设置温度值,并通知所有观察者
    public setTemperature(temperature: number): void {
      this.temperature = temperature;
      console.log("温度变化了");
      this.notifyObservers();
    }
  }
  
  // 定义一个具体的观察者类:手机
  class Phone implements DuObserver {
    // 接收被观察者的通知,并打印温度值
    public update(observable: Observable): void {
      if (observable instanceof Thermometer) {
        console.log("手机收到了温度变化的通知,温度是:" + observable.getTemperature());
      }
    }
  }
  
  // 定义一个具体的观察者类:电脑
  class Computer implements DuObserver {
    // 接收被观察者的通知,并打印温度值
    public update(observable: Observable): void {
      if (observable instanceof Thermometer) {
        console.log("电脑收到了温度变化的通知,温度是:" + observable.getTemperature());
      }
    }
  }
  
  // 测试代码
  const thermometer = new Thermometer(); // 创建一个温度计对象
  const phone = new Phone(); // 创建一个手机对象
  const computer = new Computer(); // 创建一个电脑对象
  
  thermometer.addObserver(phone); // 让手机订阅温度计
  thermometer.addObserver(computer); // 让电脑订阅温度计
  
  thermometer.setTemperature(25); // 设置温度为25
  
  thermometer.removeObserver(phone); // 让手机取消订阅
  
  thermometer.setTemperature(30); // 设置温度为30
  
//ECMAScript 2023
//https://262.ecma-international.org/14.0/
//https://github.com/tc39/ecma262

let pubObserver1="";
let pubObserver2="";
let pubObserver3="Geovin Du";
let pubObserver4="geovindu";

/**
 * The client code.
 */

const subject = new ConcreteSubject();

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

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

pubObserver2=subject.someBusinessLogic();
pubObserver3=subject.someBusinessLogic();

subject.detach(observer2);

pubObserver4=subject.someBusinessLogic();

let messageObserver: string = 'Hello World,This is a typescript!,涂聚文 Geovin Du.Web';
document.body.innerHTML = messageObserver+",<br/>one="+pubObserver1+",<br/>two="+pubObserver2+",<br/>three="+pubObserver3+",<br/>four="+pubObserver4+",<br/>TypeScript Observer Pattern 观察者模式";

  

调用:

 

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <head><title>TypeScript Hello Observer Pattern 观察者模式</title>
      <meta name="Description" content="geovindu,涂聚文,Geovin Du"/>
<meta name="Keywords" content="geovindu,涂聚文,Geovin Du"/>
<meta name="author" content="geovindu,涂聚文,Geovin Du"/> 
    </head>
    <body>
        <script src="dist/Observerts.js"></script>
    </body>
</html>

  

输出: