一个例子搞懂Observer模式

509 阅读3分钟

这篇文章主要使用类比的方法讲解observer模式,完整代码在这里

一、定义

先来看看它是怎么定义的

观察者模式是一个被称为目标的对象,将自己状态的变更自动通知给自己维护的一系列观察者的方法

单独从名字来看,这个模式的主体似乎是观察者,然而从定义中看主体却是观察者观察的目标,并且一个目标可以有多个观察者。

二、例子

举个例子,观察者模式就好像是我们自己的爱豆开通的粉丝模式(比如微博等)一样,爱豆(目标)会将自己的动态通知给所有关注(观察)自己的粉丝(观察者),这样所有的粉丝就会知道自己的爱豆做了啥

三、实现

要实现这个模式,须分析下这个模式中出现的对象

1.分析

上面的观察者(粉丝)模式中涉及到哪些对象?

显而易见的有:目标(爱豆)、观察者(粉丝)

2.实现

a.目标(爱豆)

定义中说过,目标(爱豆)是维护者一系列观察者(粉丝)的,所以在实现目标(爱豆)之前先实现ta的列表功能

// 首先列表是一个数组,每个元素都是一个观察者(粉丝)对象
class ObserverList {
    // 初始化空列表
    observerList=[];
}
// 给列表原型链上实现增加、查找、统计方法
ObserverList.prototype.Add = function(obj) {
    this.observerList.push(obj);
};
ObserverList.prototype.Get = function(index) {
    if (index > -1 && index < this.observerList.length) {
        return this.observerList[index];
    }
};
ObserverList.prototype.Count = function() {
    return this.observerList.length;
};

接下来实现目标(爱豆)类

class Subject {
    // 实例化一个空列表
    observerList = new ObserverList();
}
// 目标原型链添加增加观察者功能
Subject.prototype.Add = function(obj) {
    this.observerList.Add(obj);
};
// 目标原型链添加增加广播功能
Subject.prototype.Notify = function(news) {
    let observerListCount = this.observerList.Count();
    for (let i = 0; i < observerListCount; i++) {
        // updata需要在观察者对象上定义
        this.observerList.Get(i).Update(news);
    }
};
b.观察者(粉丝)

观察者类更简单,只需要负责更新目标的变更就行

class Observer {
    Update(){
        // 具体需要在实例化中来定义
    }
}
c.关联

接下来通过一个例子实现观察者模式

不过我们先要准备一个工具函数,将一个对象的属性可以扩展到另一个对象

// 扩展对象
function extend(obj, extension) {
    for (const key in obj) {
        extension[key] = obj[key];
    }
}

我们使用一个input模拟目标(爱豆),使用多个input模拟观察者(粉丝)

具体看代码、

<button id="addObserver">关注这个爱豆</button>
<input id="subject" type="text" placeholder="哎,我是别人的爱豆" />
<div id="container"></div>
var addObserver = document.getElementById("addObserver"),
    subject = document.getElementById("subject"),
    container = document.getElementById("container"),
    num = 0;
// 通过扩展函数,可以实例化一个目标,ta是个dom元素
extend(new Subject(), subject);
// 当目标失去聚焦时触发目标(爱豆)的广播功能
subject.onblur = new Function("subject.Notify(subject.value)");
// 每个点击事件都是添加一个观察者对象
addObserver.onclick = () => {
    num += 1;
    // 创建一个节点,ta代表一个观察者(粉丝)
    var node = document.createElement("input");
    node.type = "text";
    node.placeholder = "我是你的粉丝" + num;
    // 同样的道理,将观察者类(粉丝)的所有属性和方法扩展给每个观察者(粉丝)
    extend(new Observer(), node);
    // 目标(爱豆)的观察者(粉丝)+1
    subject.Add(node);
    // 这里就是我们具体自定义updata函数的地方
    node.Update = value => {
      node.value = value;
    };
    // 将节点添加到容器中
    container.appendChild(node);
};

现在你可以通过点击关注按钮,创建很多观察者(粉丝),在目标(爱豆)输入框输入内容,当失去聚焦时,所有观察者(粉丝)都会一起更新目标的最新动态

写在后面

observer模式只是观察者模式的一种,除了observer模式还有发布/订阅者模式,它们都是一对多的设计理念,一个变化,所有的观察者都会接收到通知。

如果我的文章有错误,诚恳的希望您可以指出,我们一起进步