观察者模式主要由一个目标对象(Subject)和一系列观察者(Observer)组成,如果目标对象发生改变,目标就会通知对应的观察者,每个观察者接收到通知后做出自己的变化。一个目标对象(Subject)可以管理自己的观察者(Observer),并且具有通知的方法,下面我们用代码来实现。

// 观察者列表,可以对观察者进行增加,修改等操作
// Subject会用到ObserverList来管理观察者
function ObserverList() {
    this.observerList = [];
}

ObserverList.prototype.Add = function(obj){
    // body... 
    return this.observerList.push(obj);
};

ObserverList.prototype.Empty = function(){
    // body... 
    this.observerList = [];
};

ObserverList.prototype.Count = function(){
    // body... 
    return this.observerList.length;
};

ObserverList.prototype.Get = function(index){
    // body... 
    if(index > -1 && index < this.observerList.length) {
        return this.observerList[index]
    }
};

ObserverList.prototype.Insert = function(obj , index){
    // body... 
    var pointer = -1;

    if(index === 0) {
        this.observerList.unshift(obj);
    }
    if(index === this.observerList.length) {
        this.observerList.push(obj);
    }
    pointer = index;
    this.observerList.splice(index,0,obj);
    return pointer;
};

ObserverList.prototype.IndexOf = function(obj, startIndex){
    // body... 
    var i = startIndex, pointer = -1;

    while(i<this.observerList.length) {
        if(this.observerList[i] === obj) {
            pointer = i
        }
        i++;
    }
    return pointer
};

ObserverList.prototype.RemoveIndexAt = function(index){
    // body... 
    if( index === 0 ) {
        this.observerList.shift()
    }
    if( index === this.observerList.length ) {
        this.observerList.pop()
    }
    this.observerList.splice(index,1);
};

目标对象利用ObserverList来管理观察者,并具有通知的方法

//目标
function Subject() {
    this.observers = new ObserverList();
}

Subject.prototype.AddObserver = function(observer){
    this.observers.Add(observer)
};

Subject.prototype.RemoveObserver = function(observer){
    this.observers.RemoveIndexAt(this.observers.indexOf(observer, 0))
};

Subject.prototype.Notify = function(context){
    var observerCount = this.observers.Count()
    for (var i = observerCount - 1; i >= 0; i--) {
        // 收到通知后调用观察者的Update方法
        this.observers.Get(i).Update(context)
    }
};

观察者具有一个Update方法,每个观察者根据自己的业务来重写Update方法,

function Observer() {
    this.Update = function() {
        console.log('默认实现')
    }
}

最后实现一个extend方法,来扩展对象

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

这样,观察者模式就实现了,下面我们用实际的例子来说明一下观察者模式的用法。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <!-- 按钮,每次点击会增加一个checkbox,每个checkbox都是一个观察者(Observer) -->
    <button id="addNewObserver"> Add New Observer checkbox</button>
    <!-- 目标对象Subject,每次点击后会把checked的值用通知发出去 -->
    <input type="checkbox" id="mainCheckbox">
    <!-- 容器,新增的checkbox会放在该容器中 -->
    <div id="observerContainer"></div>
    <script>
        // 引用DOM
        var controlCheckbox = document.getElementById('mainCheckbox');
        var addButton = document.getElementById('addNewObserver');
        var container = document.getElementById('observerContainer');

        // 具体目标
        // 利用目标扩展 controlCheckbox
        extend(controlCheckbox, new Subject() );

        // 点击checkbox会触发通知到观察者
        // 在Subject添加点击事件,点击后会将checked的值通知出去
        controlCheckbox.addEventListener('click', new Function("controlCheckbox.Notify(controlCheckbox.checked)"))
        // 添加观察者按钮点击事件
        addButton.addEventListener('click', addNewObserver);

        // 具体观察者
        function addNewObserver() {
            //创建需要添加的checkbox
            var check = document.createElement("input");
            check.type = 'checkbox';
            // 将新增的checkbox变为一个观察者
            extend(check, new Observer());
            // 重写Update方法
            check.Update = function (value) {
                check.checked = value;
            }
            // subject将observer加入队列
            controlCheckbox.AddObserver(check);
            // 将dom加到容器中
            container.appendChild(check)
        }
    </script>

</body>
</html>

运行后的效果大家可以自己去尝试一下,新增的checkBox的勾选状态会和第一个checkBox,也就是Subject保持一致。


geology
176 声望6 粉丝

自学前端