设计模式之单例模式、发布订阅模式、观察者模式代码实现

1.单例模式

class LoginFrame {
            static instance;
            constructor(state){
                this.state = state;
                if (!LoginFrame.instance) {
                  // 创建唯一实例的代码
                  LoginFrame.instance = this;
                }
                return LoginFrame.instance;
            }
            // 通过静态方法获取静态属性instance上是否存在实例,如果没有创建一个并返回,反之直接返回已有的实例
            // 全局访问点,获取唯一实例
            static getInstance(state){
                console.log('instance--->', this, this.instance)
                if(!this.instance){
                    this.instance = new LoginFrame(state)
                }
                return this.instance
            }
        }
        const p1 = LoginFrame.getInstance('show')
        const p2 = LoginFrame.getInstance('hide')
        console.log(p1 === p2) // true

2.观察者模式

 /*----------------------观察者模式---------------------------*/
        // 要求:医院预约系统 当患者订阅了某一个科室 当某一个科室发布消息的时候 通知患者

        // 目标对象(医院)
        class Subject {
            constructor() {
                this.observerList = {}; // 医院的信息库(即观察者的集合),用来存储患者的信息 { xxx(科室名): [{ yyy(患者信息1) }, { yyy(患者信息1) }] }
                this.type = ''; // 需要发布的科室
            }

            // 将患者添加进医院信息库
            add(info) {
                const  { type } = info || {};
                if (!this.observerList[type]) {
                    this.observerList[type] = [];
                }
                // 避免重复添加患者信息
                if(this.observerList[type].find(item => item.name === info.name)) {
                    return;
                }
                this.observerList[type].push(info);
            }

            // 取消订阅
            remove(info) {
                const { type } = info;
                if (!this.observerList[type].find(item => item.name === info.name)) {
                    console.log('抱歉,暂未收到您的订阅信息!')
                    return;
                }
                const index = this.observerList[type].findIndex(item => item.name === info.name);
                this.observerList[type].splice(index, 1);
            }

            // 发布信息
            notify(type) {
                this.type = type;
                this.observerList[this.type].forEach(item => {
                    item.update();
                });
            }
        }

        // 观察者(患者)
        class Observer {
            // 构造函数中记录患者的姓名 预约科室 预约时间
            constructor(name, type, time) {
                    this.name = name; // 患者姓名
                    this.type = type; // 挂号科室
                    this.time = time; // 挂号时间
            }

            // 自己定义收到订阅消息后的方法(例如患者受到消息之后是否选择就诊还是放弃等)
            update() {
                console.log(`尊敬的${this.name}:您预约的${this.type}诊治将要在${this.time}开始了!`);
            }
        }

        const subject = new Subject();

        const observer1 = new Observer('李成', '口腔科', '2023-2-23');
        const observer2 = new Observer('傅建良', '肛肠科', '2023-2-22');
        const observer3 = new Observer('杨苏文', '妇产科', '2023-1-20');
        const observer4 = new Observer('杨苏文', '妇产科', '2023-1-20');

        subject.add(observer1);
        subject.add(observer2);
        subject.add(observer3);
        subject.add(observer4);

        subject.remove(observer2);

        subject.notify('口腔科');
        subject.notify('肛肠科');
        subject.notify('妇产科');

3.发布订阅模式

/*----------------------发布订阅模式---------------------------*/
        // 要求:医院预约系统 当患者通过一款APP订阅了某一个科室 当某一个科室发布的消息的时候 APP通知患者

        // 相当于这款APP
        class EventEmit { 
            constructor() {
                this.events = {}; // 事件中心 格式: { 科室1: [ ], 科室2": [], 科室3: [] }
            }

            // 添加事件的方法
            // type为订阅类型 callback为发布消息之后执行的回调函数
            on(type, callback) {
                if (!this.events[type]) {
                    this.events[type] = [];  
                }
                this.events[type].push(callback);
            }


            emit(type, ...args) {
                if (this.events[type]) {
                    this.events[type].forEach(callback => callback(...args));
                }
            }

            remove(type, callback) {
                if (!this.events[type]) {
                    console.log(`没有订阅该事件: ${type}`)
                    return;
                }
                delete this.events[type];
                callback();
            }

            removeAll(callback) {
                this.events = [];
                callback();
            }
        }

        const eventEmit = new EventEmit();
        eventEmit.on('肛肠科', info => {
            console.log('这是肛肠科的消息1', info)
        });
        eventEmit.on('肛肠科', info => {
            console.log('这是肛肠科的消息2', info)
        });
        eventEmit.on('口腔科', info => {
            console.log('这是口腔科的消息', info)
        });
        eventEmit.on('口腔科2', info => {
            console.log('这是口腔科的消息2', info)
        });

        eventEmit.removeAll(() => {
            console.log('删除全部订阅消息成功!')
        });

        eventEmit.remove('口腔科2', () => {
            console.log('删除口腔科2的订阅消息成功!')
        });

        eventEmit.remove('妇产科', () => {
            console.log('删除妇产科的订阅消息成功!')
        });

        

        eventEmit.emit('肛肠科', '李成');
        eventEmit.emit('口腔科', '王明细');
        eventEmit.emit('口腔科2', '多尔衮');

总结:

A,单例模式是一种常用的设计模式,它保证一个类只有一个实例,并提供了一个全局访问点。在JavaScript中,单例模式可以用来管理全局变量、缓存数据等。

B,观察者模式和发布订阅模式都是常用的事件模型,它们都实现了解耦合的目的,但是其本质上还是有一些区别的。

1. 对象间通信方式不同

观察者模式中,被观察者对象(Subject)直接向观察者(Observer)对象发送消息,即Subject直接调用Observer的方法,实现了一对多的关系。而在发布订阅模式中,发布者(Publisher)和订阅者(Subscriber)之间并没有直接的联系,而是通过消息代理(Message Broker)来进行通信,实现了多对多的关系。

2. 松散耦合程度不同

观察者模式中,被观察者对象及其观察者是相互知道的,即被观察者对象需要维护一个观察者列表,并且通知到每个观察者。而在发布订阅模式中,发布者和订阅者之间是松散耦合的,他们并不需要彼此知道,通过消息代理统一处理即可。

3. 代码复杂度不同

观察者模式在实现过程中需要手动管理观察者列表,增加和删除观察者比较麻烦,同时也容易出现循环引用等问题。而在发布订阅模式中,由于使用了消息代理,订阅和发布的过程变得简单明了,代码实现起来也更加容易。

总之,两种模式都是常用的事件模型,在项目开发中可以根据需求选择合适的模式。如果需要一对多的观察模式,则使用观察者模式;如果需要多对多的事件模型,则使用发布订阅模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值