Cuuube / blog

blog on Mirror
1 stars 0 forks source link

[设计模式][js]一周一个设计模式之——观察者模式 #60

Open Cuuube opened 6 years ago

Cuuube commented 6 years ago

一周一个设计模式之——观察者模式

简介

观察者模式是一种行为型模式。

应用于主题(Subject)的状态(state)改变,如何通知观察者(Observer)们的问题。

例子

悟空八戒悟净偷看七仙女洗澡。

七仙女洗或不洗,决定着三人接下来的行动。

看代码

tips: 以下代码可直接复制到浏览器控制台运行:)

/**
 * 观察者模式:
 * 主要可用于广播。
 * 或者单体状态改变,引起多对象的改变
 * 
 * 需要一个动作发出者,即被观察者。
 * 多个观察者
 */

class Subject {
    constructor () {
        this.observerList = [];
        this.m_state = '';
    }

    register (observer) {
        this.observerList.push(observer);
        console.log('添加一个观察者!');
    }

    unregister (observer) {
        if (this.observerList.indexOf(observer) > -1) {
            this.observerList.splice(this.observerList.indexOf(observer), 1);
            console.log('删除一个观察者!');
        }
    }

    boardcast (value) {
        this.observerList.forEach((observer) => {
            observer.action(value);
        })
    }

    get state () {
        return this.m_state;
    }

    set state (value) {
        this.m_state = value;
        console.log('状态改变为:' + this.state);
        this.boardcast(this.state);
    }
}

class Observer {
    constructor (subject) {
        this.subject = subject;
    }

    action (value) {
        new Error('请勿直接调用抽象类的方法!');
    }
}

function main () {
    class 洗澡者 extends Subject {
        constructor (name) {
            super();
            this.name = name;
        }

        register (observer) {
            console.log(observer.name + '来偷看了!');
            super.register(observer);
        }

        unregister (observer) {
            console.log(observer.name + '走了!');
            super.unregister(observer);
        }
    }

    class 偷看洗澡者 extends Observer {
        constructor (name, subject) {
            super(subject);
            this.name = name;
            console.log('俺' + this.name + '来了!');
        }

        action (value) {
            switch (value) {
                case 'start':
                    console.log(this.name + '说:开始洗澡了!');
                    break;
                case 'continue':
                    console.log(this.name + '说:安全了,继续看!');
                    break;
                case 'stop':
                    console.log(this.name + '说:好像被发现了,快跑!');
                    break;
            }
        }
    }

    let 洗澡的七仙女 = new 洗澡者('七仙女');
    let 偷看洗澡的悟空 = new 偷看洗澡者('悟空', 洗澡的七仙女);
    let 偷看洗澡的八戒 = new 偷看洗澡者('八戒', 洗澡的七仙女);
    let 偷看洗澡的悟净 = new 偷看洗澡者('悟净', 洗澡的七仙女);

    洗澡的七仙女.register(偷看洗澡的悟空);
    洗澡的七仙女.register(偷看洗澡的八戒);
    洗澡的七仙女.register(偷看洗澡的悟净);

    洗澡的七仙女.state = 'start';
    洗澡的七仙女.unregister(偷看洗澡的悟空);
    洗澡的七仙女.state = 'stop';
    洗澡的七仙女.unregister(偷看洗澡的悟净);
    洗澡的七仙女.state = 'continue';
}

main();

输出:

$ node observer.js

俺悟空来了!
俺八戒来了!
俺悟净来了!
悟空来偷看了!
添加一个观察者!
八戒来偷看了!
添加一个观察者!
悟净来偷看了!
添加一个观察者!
状态改变为:start
悟空说:开始洗澡了!
八戒说:开始洗澡了!
悟净说:开始洗澡了!
悟空走了!
删除一个观察者!
状态改变为:stop
八戒说:好像被发现了,快跑!
悟净说:好像被发现了,快跑!
悟净走了!
删除一个观察者!
状态改变为:continue
八戒说:安全了,继续看!

为了讲解,变量用了汉字。生产用代码请勿使用汉字当变量名和类名!!!