发布订阅者模式

176 阅读2分钟

js 四种异步变成模式:回调函数、事件监听、发布订阅模式、promise(yield/await),其实事件监听跟发布订阅模式很像,也是触发函数调用(回调函数),所以前三者有很大的相似之处。

1.类的解耦

发布订阅者模式,对象或者类的解耦!

const Oberver = (function () {
    // 防止消息队列暴露而被篡改个,故将消息容器作为静态私有变量保存
    const _messages = {};
    return {
        // 注册信息接口
        regist(type, fn) {
            if (typeof _messages[type] === 'undefined') {
                _messages[type] = [fn];
            } else {
                _messages[type].push(fn);
            }
            return this;
        },
        // 发布信息接口
        fire(type, msg) {
            if (!_messages[type]) {
                return;
            }
            // 发布的消息
            const event = {
                type,
                msg
            }
            for (let i = 0; i < _messages[type].length; i++) {
                // _message不能被 垃圾回收机制 回收 产生闭包, 内存不会被释放,泄漏中...
                _messages[type][i].call(this, event);
                // _messages[type][i](event); // 不替换this暂时也可以
            }
        },
        // 移除信息接口
        remove(type, fn) {
            // 如果 消息类型(消息动作序列)存在
            if (_messages[type] instanceof Array) {
                let i = _messages[type].length - 1;
                for (; i >= 0; i--) {
                    // 如果存在 ‘该动作’ 则 在消息动作序列 移除相应动作
                    _messages[type][i] === fn && _messages[type].splice(i, 1);
                }
            }
            return this;
        }
    }
})();

// 实际测试使用
// A订阅一个test1
Oberver.regist('test1', function (e) {
    console.log('我是A用户');
    console.log(e);
});
// B订阅一个test1
Oberver.regist('test1', function (e) {
    console.log('我是B用户');
    console.log(e);
})

// 监听着开始发布
Oberver.fire('test1', {
    data: '通知,公司来了MM啊!'
});

2.组件通信

通过观察者模式我们可以解决团队开发过程中的模块间通信,这是模块间解耦的一种可行性方案

const Observer = (function () {
    // 消息队列
    const _message = {};
    return {
        regist(type, fn) { // 订阅、注册、监听
            if (!Array.isArray(_message[type])) { // 类型不存在
                _message[type] = [fn];
            } else {
                _message[type].push(fn);
            }
        },
        fire(type, data) { // 发布消息
            const res = {
                type,
                data
            }
            if (!Array.isArray(_message[type])) {
                return;
            }
            for (let i = 0; i < _message[type].length; i++) {
                _message[type][i].call(this, res);
            }
        },
        remove(type, fn) { // 移除订阅、注册、监听
            if (!Array.isArray(_message[type])) {
                return;
            }
            let len = _message[type].length,
                i = _message[type].length - 1;
            for (; i >= 0; i--) {
                _message[type][i] === fn && _message[type].splice(i, 1);
            }
        }
    }
})();

// 实际使用----------------------------------------->
// 创建学生类
function Student(result) {
    var that = this;
    this.result = result;
    this.say = function (e) {
        // console.log(e);
        console.log(that.result);
    }
};
Student.prototype.answer = function (question) {
    // 注册监听 在父级上
    Observer.regist(question, this.say);
}

Student.prototype.sleep = function (question) {
    // 取消监听 在父级上
    Observer.remove(question, this.say);
}

// 创建老师类
function Teacher() {};
Teacher.prototype.ask = function (question) {
    console.log('老师发布的问题是:' + question);
    Observer.fire(question,{msg:'真棒!'})
}

// 创建机器学生
const student1 = new Student('学生1开始回答问题');
const student2 = new Student('学生2开始回答问题');
const student3 = new Student('学生3开始回答问题');
// 学生监听问题类型
student1.answer('什么是设计模式');
student1.answer('发布订阅这模式是?');
student2.answer('什么是设计模式');
student2.answer('发布订阅这模式是?');
student3.answer('什么是设计模式');
student3.answer('发布订阅这模式是?');

// 但是有学生睡着了(down机了)取消注册、订阅、监听
student2.sleep('发布订阅这模式是?');
student3.sleep('什么是设计模式');

// -------------老师正式开始提问---------->
const techer = new Teacher();
techer.ask('什么是设计模式'); // 类型1
techer.ask('发布订阅这模式是?'); // 类型2