【译】TypeScript 实现观察者设计模式

615 阅读3分钟

原文地址:Observer Design Pattern Implementation in Typescript | by Poorshad Shaddel | Level Up Coding (gitconnected.com)

在这篇文章中,我们将学习观察者设计模式的使用方法。

观察者设计模式的定义

根据 GoF (设计模式四巨头),观察者模式在对象之间定义了一对多的依赖关系,因此当一个对象改变状态时,其所有的依赖对象都会被通知并自动更新。它也被称为发布-订阅模式。

简单来讲,当你想知道另一个对象的变化时,你可以使用观察者设计模式

观察者设计模式是一种行为模式,它意味它是一种对象之间的通信模式。

这种设计模式的其他名称是: 事件分发订阅监听器模式, 发布订阅模式

这类设计模式在现实生活中有那些案例?

社交应用是这种设计模式的现实世界的例子。当我们在Instagram上关注某人时,我们只是想知道这个人的状态变化。

如果你正在使用NodeJS或Javascript,那你应该熟悉事件监听器。我们监听一个对象,然后根据对象的变化做出反应。例如,当输入值发生变化时,我们想再次计算一些东西。这通常与我们想通过使用观察者设计模式来做的事情非常相似。

设计模式 UML

让我们看一下UML,之后,我们将使用typescript实现一个简单的例子。

1_Jhtau0xFtdXyJlOSqNRZhw.png

Subject 是我们想要了解的东西。它包含了一些方法,我们可能在不同的文章中看到过不同的名字。

  • registerObserver = register = attach = subscribe:此方法用于添加一个观察者。
  • unregisterObserver = unregister = detach = unsubscribe: 此方法用于移除观察者。
  • notifyObserver = notify: 此方法将在每个观察者之上运行一个方法,这个方法将通知观察者有什么变化。
  • update: 当 Subject 改变的时候,我们会运行这个方法。

廉价的谈话!

让我们看看如何用Typescript实现这一点。

首先,我们应该安装Typescript,将我们的代码转译成JavaScript。

npm init -y
npm install typescript

让我们来创建typescript文件:

interface ISubject {
    subscribe(observer: Observer):void                
    unsubscribe(observer: Observer):void 
    notify():void 
}
interface IObserver { 
    update():void 
}
class Subject implements ISubject { 
    private observers:Observer[] = [];                
    subscribe(observer:Observer) {                     
        this.observers.push(observer)                       
    }
    unsubscribe(observer:Observer) {
        this.observers = this.observers.filter((element)=>{ 
            return observer.id === element.id                
        })   
    }  
    notify() {                                          
        this.observers.forEach(observer => {                
             observer.update();                                  
        })
    }                                                   
}                                                   
class Observer implements IObserver {               
     constructor(public readonly id:number) {}           
     update() {                                          
        console.log(`Observer ${this.id} is updating...`) 
     }                                                   
}                                                   

const firstObserver = new Observer(1);              
const secondObserver = new Observer(2);             
                                                
const subject = new Subject();                      
                                                  
subject.subscribe(firstObserver);                   
subject.notify();                                   
 console.log("-----")                                
subject.subscribe(secondObserver);                  
subject.notify();                                   
console.log("-----")                                
subject.unsubscribe(secondObserver);                
subject.notify();

实现之后,我们在第35行和第36行创建了两个观察者。在第38行,我们创建了一个 subject。

在第40行,firstObserver 订阅了这个主题。所以如果我们运行 notify,我们应该只看到 firstObserver 的日志。

在第42行,我们订阅了 secondObserver,所以如果现在运行 notify,我们应该看到这两个观察员的日志。

在第46行,我们取消了对 secondObserver 的订阅,所以如果执行 notify,我们应该只看到 firstObserver 的日志。 最后,日志应该是这样的:

[LOG]: "Observer 1 is updating..."
[LOG]: "-----"
[LOG]: "Observer 1 is updating..."
[LOG]: "Observer 2 is updating..."
[LOG]: "-----"
[LOG]: "Observer 2 is updating..."

让我们实施一些更有意义的东西吧!

interface ISubject {
    subscribe(observer: Observer):void
    unsubscribe(observer: Observer):void
    notify(news:String):void
}

interface IObserver {
    update(news:string):void
}

class CR7SocialMedia implements ISubject {
    private observers:Observer[] = [];
    subscribe(observer:Observer) {
        this.observers.push(observer)
    }
    unsubscribe(observer:Observer) {
        this.observers = this.observers.filter((element)=>{
            return observer.name === element.name
        })
    }
    notify(news:string) {
        this.observers.forEach(observer => {
            observer.update(news);
        })
    }
}

class Observer implements IObserver {
    constructor(public readonly name:string) {}
    private feed:string[] = []; 
    update(news:string) {
        this.feed.push(news)
       console.log(`${this.name} recieved  a news`)
    }
    showFeed() {
        console.log(this.name + ":" + this.feed)
    }
}

const firstFan = new Observer("alice");
const secondFan = new Observer("bob");

const cr7 = new CR7SocialMedia();

cr7.subscribe(firstFan);
cr7.subscribe(secondFan);
cr7.notify("CR7 has sent off");
cr7.unsubscribe(secondFan);
cr7.notify("CR7 scored a goal against Inter Milan.");
firstFan.showFeed();
secondFan.showFeed()

想象一下,我们有 CR7 的社交页面,我们想关注这个页面的新闻。每个想关注这个页面的人都应该订阅他,每次有新闻的时候,我们都会调用 notify 函数,然后我们传递新闻,这个函数将新闻传递给关注者,他们的更新实现可以很容易地将这个新闻添加到他们的 feed 数组中。之后,通过调用 showFeed 函数我们可以看到这些关注者的 feed

这就是我们应该在控制台看到的输出:

[LOG]: "alice recieved  a news"
[LOG]: "bob recieved  a news"
[LOG]: "bob recieved  a news"
[LOG]: "alice:CR7 has sent off"
[LOG]: "bob:CR7 has sent off,CR7 scored a goal against Inter Milan."

这是对这种设计模式的一个简单实现。就我个人而言,我只有在看到一些例子时才能理解这种东西,这篇文章的目的是通过使用简单的例子和用法来解释这种设计模式。

参考文献

howtodoinjava.com/design-patt….

refactoring.guru/design-patt…