设计模式-观察者模式 js/ts实现

基于大话设计模式使用js和ts复写

解释

主题(subject) 和 观察者(observer),一个Subject可以拥有任意数目依赖它的Observer,一旦它的状态发生改变,所有的Observer都能收到通知。

Subject发通知并不需要谁是观察者,任何一个观察者也不需要其他观察者存在

当订阅者的更新方法不一样时,需要使用委托,原文是使用的c#,此处使用的js,由于没有委托,因此尝试使用函数实现

观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。

image-20240118182725690

JS

主题和观察者 抽象类

// 主题类
class Subject{
    Attach(observer){} // 添加观察者
    Detach(observer){} // 删除观察者
    Notify(){} // 通知方法

    getSecretaryAction(){} // 获取自定义文本
    setSecretaryAction(action){} // 写入自定义文本
}
// 主题-具体
class Boss extends Subject {
    action = ''
    observers = []

    Attach(observer){
        this.observers.push(observer)
    }
    Detach(observer){
        let index = this.observers.indexOf(observer)
        this.observers.splice(index,1)
    }
    Notify(){
        this.observers.forEach(item => item.Update())
    }

    getSecretaryAction(){
        return this.action
    }
    setSecretaryAction(action){
        this.action = action
    }
}
// 观察者类
class Observer {
    constructor(name,sub){
        this.name = name
        this.sub = sub
    }
    Update(){}
}
// 看股票的同事
class StockObserver extends Observer {
    Update(){
        console.log(`${this.name} ${this.sub.getSecretaryAction()} 关闭股票行情继续工作`)
    }
}

// 看NBA的同事
class NbaObserver extends Observer {
    Update(){
        console.log(`${this.name} ${this.sub.getSecretaryAction()} 关闭NBA继续工作`)
    }
}

function main (){
    let secreatry = new Boss()
    let a = new StockObserver('滕笑然',secreatry)
    let b = new NbaObserver('胡汉三',secreatry)
    secreatry.Attach(a)
    secreatry.Attach(b)
    secreatry.setSecretaryAction('老板回来了!!!!')
    secreatry.Notify()
}
main()

委托类型

之所以使用委托类型,再使用三方组件的时候,可能提供了观察者的更新方法,但是这个方法名称我们不可能去改,各种各样的三方组件可能有不同的名称,此时我们要使用委托类型来解决这种方法,从外部能够自定义调用的更新方法

原文中的委托是使用c#实现的,没有找到合适的方法,暂时使用数组遍历调用,若有其他专业方法再更新

注意:由于js的this指向问题,函数指向运行时的调用者,所以此处要使用bind或者回调函数来保持this的指向,此处两种都做了演示

// 观察者模式
// 抽象-通知者
class Subject{
    Notify(){} // 通知方法
    getSecretaryAction(){} // 获取自定义文本
    setSecretaryAction(action){} // 写入自定义文本
}
// 具体-通知者
class Boss extends Subject {
    action = '' // 自定义文本

    Notify(arr){
        arr.forEach(item => item())
    }

    getSecretaryAction(){
        return this.action
    }

    setSecretaryAction(action){
        this.action = action
    }
}

// 具体-观察者 看股票的同事
class StockObserver{
    constructor(name,sub){
        this.name = name
        this.sub = sub
    }
    StockUpdate(){
        console.log(`${this.name} ${this.sub.getSecretaryAction()} 关闭股票行情继续工作`)
    }
}

// 具体-观察者 看NBA的同事
class NbaObserver {
    constructor(name,sub){
        this.name = name
        this.sub = sub
    }
    NbaUpdate(){
        console.log(`${this.name} ${this.sub.getSecretaryAction()} 关闭NBA继续工作`)
    }
}

function main (){
    let secreatry = new Boss()
    let a = new StockObserver('tengyao',secreatry)
    let b = new NbaObserver('zhangning',secreatry)
    secreatry.setSecretaryAction('老板回来了!!!!')
    secreatry.Notify([a.StockUpdate.bind(a),()=>b.NbaUpdate()]) // 此处使用回调函数和react一样,让后面的函数指向了a
}
main()

TS

主题和观察者 抽象类

// 抽象 主题
abstract class Subject2 {
    public abstract Attach(observer:Observer2):void // 抽象 添加观察者方法
    public abstract Detach(observer:Observer2):void // 抽象 删除观察者方法
    public abstract get SecretaryAction():string; // 获取自定义文本
    public abstract set SecretaryAction(action:string); // 删除自定义文本
    public abstract Notify(); // 通知方法
}

// 抽象 观察者
abstract class Observer2 {
    protected name:string ; // 观察者名称
    protected sub:Subject2; // 主题
    constructor(name:string,sub:Subject2){
        this.name = name
        this.sub = sub
    }
    public abstract Update():void;
}

class Secretary2 extends Subject2 {
    private observers:StockObserver2[]  = []
    private action:string ;

    public Attach(observer:StockObserver2):void{
        this.observers.push(observer)
    }
    public Detach(observer:StockObserver2):void{
        let index:number = this.observers.indexOf(observer)
        this.observers.splice(index,1)
    }
    public Notify():void{
        this.observers.forEach((item:StockObserver2) => item.Update())
    }
    public get SecretaryAction():string{
        return this.action
    }
    public set SecretaryAction(action:string){
        this.action = action
    }

}

class StockObserver2 extends Observer2 {
    constructor(name:string,sub:Subject2){
        super(name,sub) //使用super用于继承父类方法
    }
    public Update():void{
        console.log(`${this.name} ${this.sub.SecretaryAction} 关闭股票行情继续工作`)
    }
}

class NBAObserver2 extends Observer2 {
    constructor(name:string,sub:Subject2){
        super(name,sub)
    }
    public Update():void{
        console.log(`${this.name} ${this.sub.SecretaryAction} 关闭NBA继续工作`)
    }
}

function main1 ():void{
    let secreatry2:Secretary2 = new Secretary2()
    let a:StockObserver2 = new StockObserver2('王腾瑶',secreatry2)
    let b:StockObserver2 = new NBAObserver2('张宁',secreatry2)
    secreatry2.Attach(a)
    secreatry2.Attach(b)
    secreatry2.SecretaryAction = '老板回来了!!!!'
    secreatry2.Notify()
}

main1()

委托类型

ts目前百度没有找到委托类型,暂时使用一个变量存储函数,具体实现和js原理一致

abstract class Subject3 {
    public abstract get SecretaryAction():string; // 抽象 获取自定义文本
    public abstract set SecretaryAction(action:string); // 写入 获取自定义文本
    public abstract Notify(); // 通知方法
}

type CalculationDelegate = () => void;//自定义类型

class Secretary3 extends Subject3 {
    private action:string ;
    private UpdateArr:CalculationDelegate[] = []; //存储 观察者更新函数 的数组
    // 通知观察者方法
    public Notify():void{
        this.UpdateArr.forEach((fn:CalculationDelegate) =>  fn())
    }
  	// 用于添加 观察者更新函数
    public  Update(fn:CalculationDelegate){
        this.UpdateArr.push(fn)
    }
    public get SecretaryAction():string{
        return this.action
    }
    public set SecretaryAction(action:string){
        this.action = action
    }
}

class StockObserver3  {
    private name:string ;
    private sub:Secretary3;
    constructor(name:string,sub:Secretary3){
        this.name = name
        this.sub = sub
    }
    public stockUpdate():void{
        console.log(`${this.name} ${this.sub.SecretaryAction} 关闭股票行情继续工作`)
    }
}

class NBAObserver3  {
    private name:string ;
    private sub:Secretary3;
    constructor(name:string,sub:Secretary3){
        this.name = name
        this.sub = sub
    }
    public nbaUpdate():void{
        console.log(`${this.name} ${this.sub.SecretaryAction} 关闭NBA继续工作`)
    }
}

function main1 ():void{
    let secretary3:Secretary3 = new Secretary3()
    let a:StockObserver3 = new StockObserver3('王腾瑶',secretary3)
    let b:NBAObserver3 = new NBAObserver3('张宁',secretary3)
    secretary3.Update(a.stockUpdate.bind(a)) // 添加a的观察方法
    secretary3.Update(b.nbaUpdate.bind(b)) // 添加b的观察方法
    secretary3.SecretaryAction = '老板回来了!!!!'
    secretary3.Notify()
}

main1()

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值