设计模式:TypeScript中的观察者模式

​掌握观察者模式和发布订阅模式的实现和应用场景。

欢迎来到 TypeScript 设计模式系列,该系列介绍了使用 TypeScript 进行 Web 开发的一些有用的设计模式。

之前的文章如下:


设计模式对 web 开发人员非常重要,掌握它们可以让我们写出更好的代码。在这篇文章中,我将使用 TypeScript 来介绍观察者模式和发布订阅模式。


观察者模式
 

观察者模式在Web世界中应用广泛,
MutationObserver
IntersectionObserver
PerformanceObserver
ResizeObserver
ReportingObserver。这些API都可以看到观察者模式.此外,该模式还用于事件监控和数据响应(例如当数据发生变化时,页面会自动更新)。

观察者模式定义了一对多的关系,允许多个观察者对象同时监视一个主对象。当主对象的状态发生变化时,所有观察者对象将被通知,以便它们可以自动更新。

观察者模式中有两个主要角色:主体和观察者。

在上面的图中,Subject 是 my article,观察者是 chris1993 和 bytefish. 由于观察者模式支持简单的广播通信,当新文章发布时,所有观察者都会被自动通知。

为了更好地理解下面的代码,让我们先看看相应的 UML 类图:

在上图中,我们使用interface分别定义了 Observer 和 Subject 接口,用于描述观察者和主体对象。

观察者接口

interface Observer {  notify(article: Article): void;}


主题接口

interface Subject {  observers: Observer[];  addObserver(observer: Observer): void;  deleteObserver(observer: Observer): void;  notifyObservers(article: Article): void;}

然后,我们分别定义上述接口的实现类:ConcreteObserver 和 ConcreteSubject

ConcreteObserver类

class ConcreteObserver implements Observer {  constructor(private name: string) {}  notify(article: Article) {    console.log(`"Article: ${article.title}" has been sent to  ${this.name}.`);  }}


ConcreteSubject类

class ConcreteSubject implements Subject{  public observers: Observer[] = [];  public addObserver(observer: Observer): void {    this.observers.push(observer);  }  public deleteObserver(observer: Observer): void {    const n: number = this.observers.indexOf(observer);    n != -1 && this.observers.splice(n, 1);  }  public notifyObservers(article: Article): void {    this.observers.forEach((observer) => observer.notify(article));  }}


下面验证一下对应的函数:

const subject: Subject = new ConcreteSubject();const chris1993 = new ConcreteObserver("Chris1993");const bytefish = new ConcreteObserver("Bytefish");
subject.addObserver(chris1993);subject.addObserver(bytefish);
subject.notifyObservers({  author: "Bytefer",  title: "Observer Pattern in TypeScript",  url: "https://medium.com/***",});
subject.deleteObserver(bytefish);subject.notifyObservers({  author: "Bytefer",  title: "Adapter Pattern in TypeScript",  url: "https://medium.com/***",});


当上述代码运行成功时,终端将输出以下结果:

"Article: Observer Pattern in TypeScript" has been sent to Chris1993."Article: Observer Pattern in TypeScript" has been sent to Bytefish."Article: Adapter Pattern in TypeScript" has been sent to Chris1993.

目前,我主要写两个主题,JavaScript 和 TypeScript,所以如果我想发布一篇文章,只有对 JavaScript 或 TypeScript 感兴趣的读者才会收到通知,如果我们使用 Observer 模式,我们需要创建两个不同的 Subject,我们也可以使用 Publish-subscribe 模式。


发布-订阅模式
 

在软件架构中,发布-订阅是一种消息传递范式,其中消息的发送方(称为发布者)不直接将消息发送给特定的接收方(称为订阅者)。相反,发布的消息被分成不同的类别,并发送给不同的订阅者。同样,订阅者可以表达对一个或多个类别的兴趣,并且只接收感兴趣的消息,而不需要知道哪些发布者存在。

发布-订阅模型中主要有三个角色:发布者、渠道和订阅者。

在上图中,Publisher 是 Bytefer,Channels 中的 Topic A 和 Topic B 分别对应于 JavaScript 主题和 TypeScript 主题,Subscriber 是 chris1993、bytefish 等。

让我们基于发布-订阅模式实现一个 EventEmitter:

type EventHandler = (...args: any[]) => any;class EventEmitter {  private c = new Map<string, EventHandler[]>();  subscribe(topic: string, ...handlers: EventHandler[]) {    let topics = this.c.get(topic);    if (!topics) {      this.c.set(topic, (topics = []));    }    topics.push(...handlers);  }  unsubscribe(topic: string, handler?: EventHandler): boolean {    if (!handler) {      return this.c.delete(topic);    }    const topics = this.c.get(topic);    if (!topics) {      return false;    }    const index = topics.indexOf(handler);    if (index < 0) {      return false;    }    topics.splice(index, 1);    if (topics.length === 0) {      this.c.delete(topic);    }    return true;  }  publish(topic: string, ...args: any[]): any[] | null {    const topics = this.c.get(topic);    if (!topics) {      return null;    }    return topics.map((handler) => {      try {        return handler(...args);      } catch (e) {        console.error(e);        return null;      }    });  }}

定义了  EventEmitter  类之后,我们可以像这样使用它:

const eventEmitter = new EventEmitter();
eventEmitter.subscribe("ts",   (msg) => console.log(`Received:${msg}`));
eventEmitter.publish("ts", "Observer pattern");eventEmitter.unsubscribe("ts");eventEmitter.publish("ts", "Pub-Sub pattern");

当上述代码运行成功时,终端将输出以下结果: Received: Observer pattern 。

在事件驱动架构中,发布订阅模式发挥着重要的作用,该模式的具体实现可以作为事件总线,实现同一系统中不同组件或模块之间的消息通信,对于广泛使用的插件架构,可以用来实现不同插件之间的消息通信。

在阅读完这篇文章后,我希望你对观察者模式和发布订阅模式有一定的了解。

 欢迎关注公众号:文本魔术,了解更多

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TypeScript是一种强类型的编程语言,它是JavaScript的超集,可以编译成纯JavaScript代码。因此,在TypeScript可以应用各种设计模式,与其他面向对象编程语言类似。 下面是一些常见的设计模式,在TypeScript的应用: 1. 工厂模式(Factory Pattern):用于创建对象,隐藏具体对象的实现细节,并通过一个共同的接口来创建对象。在TypeScript,可以使用类来实现工厂模式,并通过工厂方法来创建对象。 2. 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局的访问点。在TypeScript,可以使用静态属性和方法来实现单例模式。 3. 观察者模式(Observer Pattern):定义对象间的一种一对多的依赖关系,使得当一个对象状态发生改变时,所有依赖它的对象都会得到通知并自动更新。在TypeScript,可以使用观察者模式来实现事件和订阅/发布模式。 4. 策略模式(Strategy Pattern):定义一系列算法,将它们封装起来,并且使它们可以相互替换。在TypeScript,可以使用接口和多态性来实现策略模式。 5. 适配器模式(Adapter Pattern):将一个类的接口转换成客户端所期望的另一个接口,使原本不兼容的类可以合作。在TypeScript,可以使用适配器类来实现适配器模式。 6. 装饰器模式(Decorator Pattern):动态地给一个对象添加一些额外的职责,而不需要修改其原始类。在TypeScript,可以使用装饰器来实现装饰器模式。 以上只是一些常见的设计模式,在TypeScript的应用示例。根据具体的需求,还可以结合其他设计模式来实现更复杂的功能和架构。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值