实现解耦:观察者模式的应用

观察者模式,开始接触开发的时候,就有使用到。某个值的变化,引起其他值也发生变化。这个是使用比较多的设计模式。掌握该设计模式,对开发而言是比较重要得。今天,就对该设计模式进行分析

什么是观察者模式

观察者模式:定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

观察者模式的优点

  1. 降低耦合性:观察者模式允许主题和观察者之间解耦,因为它们之间只存在抽象的观察者接口,而不存在直接的依赖关系。
  2. 增加可扩展性:观察者模式使得添加新的观察者变得容易,只需要实现观察者接口并注册到主题即可。
  3. 提高系统灵活性:观察者模式使得主题和观察者之间的通信变得灵活,可以根据需要实现推送或拉取信息的功能。

模式UML

观察者模式包含如下角色:

  • Subject: 目标
  • ConcreteSubject: 具体目标
  • Observer: 观察者
  • ConcreteObserver: 具体观察者

从UML图中,可以看出,在抽象类Subject中,通过attach将观察者加入objList中。ConcreteSubject对象中,在被观察的对象变更时,通知objList中的观察者。以达到对目标变化的监听。核心在于objList的观察者存储,与ConcreteSubject属性变化的通知。

javascript 实现

JAVASCRIPT 复制代码
let Subject = function () {
        this.objlist = []
    }

    Subject.prototype.attach = function (pObeserver) {
        this.objlist.push(pObeserver);
    }

    Subject.prototype.detach = function () {
        throw (new Error("子类必须实现此方法"))
    }

    Subject.prototype.notify = function () {
        throw (new Error("子类必须实现此方法"))
    }

    let ConcreteSubject = function () {
        Subject.apply(this, arguments)
    }
    ConcreteSubject.prototype = Object.create(Subject.prototype)
    ConcreteSubject.prototype.constructor = ConcreteSubject

    ConcreteSubject.prototype.attach = function (pObeserver) {
        this.objlist.push(pObeserver);
    }

    Subject.prototype.detach = function (pObeserver) {

        for (let index = 0; index < this.objlist.length; index++) {
            const element = this.objlist[index];
            if (element == pObeserver) {
                this.objlist.splice(index, 1)
                return
            }
        }

    }

    Subject.prototype.notify = function () {
        this.objlist.forEach(obj => {
            obj.update(this)
        });
    }

    ConcreteSubject.prototype.setState = function (state) {
        this.state = state;
        this.notify()
    }

    ConcreteSubject.prototype.getState = function () {
        return this.state
    }


    let Obsever = function () {}
    Obsever.prototype.update = function () {
        throw (new Error("子类必须实现此方法"))
    }

    let ConcreteObsever = function (name) {
        this.name = name
        this.obeserverState = ""
    }
    ConcreteObsever.prototype = Object.create(Obsever.prototype)
    ConcreteObsever.prototype.constructor = ConcreteObsever
    ConcreteObsever.prototype.update = function (sub) {
        this.obeserverState = sub.getState()

        console.log("收到" + this.name + "状态更新为:" + this.obeserverState);
    }

    let _ConcreteSubject = new ConcreteSubject();
    let _ConcreteObseverA = new ConcreteObsever("观察者A");
    let _ConcreteObseverB = new ConcreteObsever("观察者B");

    _ConcreteSubject.attach(_ConcreteObseverA)
    _ConcreteSubject.attach(_ConcreteObseverB)

    _ConcreteSubject.setState(1)
    // 收到观察者A状态更新为:1
    // 收到观察者B状态更新为:1

    _ConcreteSubject.detach(_ConcreteObseverB)
    _ConcreteSubject.setState(2)
    // 收到观察者A状态更新为:2
相关推荐
江城开朗的豌豆12 分钟前
React 跨级组件通信:避开 Context 的那些坑,我还有更好的选择!
前端·javascript·react.js
吃饺子不吃馅1 小时前
root.render(<App />)之后 React 干了哪些事?
前端·javascript·面试
鹏多多1 小时前
基于Vue3+TS的自定义指令开发与业务场景应用
前端·javascript·vue.js
江城开朗的豌豆1 小时前
Redux 与 MobX:我的状态管理选择心路
前端·javascript·react.js
吃饺子不吃馅2 小时前
✨ 你知道吗?SVG 里藏了一个「任意门」——它就是 foreignObject! 🚪💫
前端·javascript·面试
gnip10 小时前
企业级配置式表单组件封装
前端·javascript·vue.js
掘金安东尼12 小时前
抛弃自定义模态框:原生Dialog的实力
前端·javascript·github
hj5914_前端新手15 小时前
javascript基础- 函数中 this 指向、call、apply、bind
前端·javascript
Hilaku16 小时前
都2025年了,我们还有必要为了兼容性,去写那么多polyfill吗?
前端·javascript·css
LuckySusu16 小时前
【js篇】JavaScript 原型修改 vs 重写:深入理解 constructor的指向问题
前端·javascript