设计模式,发布订阅的两种实现方案

设计模式,发布订阅的两种实现方案,第1张

文章目录 一、设计模式二、发布订阅1、发布订阅的实现方案2、第二种实现方案


一、设计模式

设计模式:

单例设计模式:解决了“全局变量污染”的问题、还可以保证模块间方法的相互访问 「最早的模块化开发的思想」工厂设计模式
@1 其实就是利用“函数封装”的特点,把重复做的事情封装起来,实现“低耦合高内聚”:减少页面中冗余代码,提高代码重复使用率,提高开发效率等!
@2 在JQ源码中,基于工厂模式实现:把jQuery当做普通方法执行,也可以创造其一个实例构造函数设计模式:充分利用面向对象的思想,有效的实现了实例和实例之间的“独立性”以及“共有性”,适用于插件组件封装,例如:我们用的Swiper轮播图插件,Swiper本身就是一个类,每一次创建轮播图都是创造Swiper的一个实例!!Promise承诺者设计模式:基于promise和async/await可以有效管理异步编程的代码,防止回调地狱!!发布订阅设计模式观察者设计模式…
设计模式就是一种思想,基于这种思想可以有效的管理我们的代码;设计模式是“锦上添花”!! 二、发布订阅

1、发布订阅的实现方案
(function () {
    class Sub {
        // 给实例设置私有的事件池
        listeners = [];

        // 在原型上扩展add/remove/fire来管理事件池中的方法&通知方法执行
        // 方法中的this一般指当前类的实例 -> s1.add/remove/fire(...)
        add(func) {
            let listeners = this.listeners;
            if (listeners.includes(func)) return;
            listeners.push(func);
        }
        remove(func) {
            let listeners = this.listeners;
            let index = listeners.indexOf(func);
            if (index >= 0) {
                listeners[index] = null;
            }
        }
        fire(...params) {
            let listeners = this.listeners;
            for (let i = 0; i < listeners.length; i++) {
                let item = listeners[i];
                if (typeof item !== "function") {
                    listeners.splice(i, 1);
                    i--;
                    continue;
                }
                item(...params);
            }
        }
    }
    window.Sub = Sub;
})();

let s1 = new Sub;
let s2 = new Sub;

const fn1 = (x, y) => {
    console.log('fn1', x, y);
};
const fn2 = (x, y) => {
    console.log('fn2', x, y);
    // 移除事件池
    s1.remove(fn1);
    s1.remove(fn2);
};
const fn3 = () => console.log('fn3');
const fn4 = () => console.log('fn4');
const fn5 = () => console.log('fn5');
const fn6 = () => console.log('fn6');

// 加入事件池
s1.add(fn1);
s1.add(fn2);
s1.add(fn3);
s1.add(fn4);
s1.add(fn5);
s1.add(fn6);

s2.add(fn4);
s2.add(fn5);
s2.add(fn6);

// 通知执行
setTimeout(() => {
    s1.fire(100, 200);
    // 再过一秒再执行
    setTimeout(() => {
        s1.fire(1000, 2000);
    }, 1000);
}, 1000);
2、第二种实现方案
(function () {
    // 创建计划表
    const listeners = {};

    // 向计划表某个计划中加入方法
    const on = function on(name, func) {
        // 首先校验“name”计划在计划表中是否存在,如果不存在,则先创建这样的计划,值是空数组
        if (typeof listeners[name] === "undefined") {
            listeners[name] = [];
        }
        // 获取该计划后面的数组集合
        let arr = listeners[name];
        // 每一次加方法执行先判断「该方法是否已经在集合中存在,不允许重复加入的」
        if (arr.includes(func)) return;
        // 把需要执行的方法加入到集合中
        arr.push(func);
    };

    // 从计划表某个计划中移除方法
    const off = function off(name, func) {
        // 首先校验该计划是否存在
        if (typeof listeners[name] === "undefined") return;
        // 迭代数组中的每一项,移除对应的内容
        let arr = listeners[name];
        for (let i = 0; i < arr.length; i++) {
            if (arr[i] === func) {
                // arr.splice(i, 1); //这样会导致数组塌陷
                arr[i] = null;  //不移除,数组的索引结构就不会变
                break;
            }
        }
    };

    // 通知计划表中某个计划中的方法执行
    const emit = function emit(name, ...params) {
        if (typeof listeners[name] === "undefined") return;
        // 迭代数组每一项,把每一项执行「不要忘记把接收的实参传递给每个函数」
        let arr = listeners[name];
        for (let i = 0; i < arr.length; i++) {
            let item = arr[i];
            if (typeof item === "function") {
                item(...params);
                continue;
            }
            // 当前项不是个函数,我们把其移除「也要注意数组塌陷问题,但是先减减再加加,下一轮还是从此时的i开始」
            arr.splice(i, 1);
            i--;
        }
    };

    // 暴露API
    window["_plain"] = {
        on,
        off,
        emit
    };
})();

const fn1 = (x, y) => {
    console.log('fn1', x, y);
};
const fn2 = (x, y) => {
    console.log('fn2', x, y);
    _plain.off('marry', fn1);
    _plain.off('marry', fn2);
};
const fn3 = () => console.log('fn3');
const fn4 = () => console.log('fn4');
const fn5 = () => console.log('fn5');
const fn6 = () => console.log('fn6');

// 全部加入计划表
_plain.on('marry', fn1);
_plain.on('marry', fn2);
_plain.on('marry', fn3);
_plain.on('marry', fn4);
_plain.on('marry', fn5);
_plain.on('marry', fn6);

// 一秒后通知执行
setTimeout(() => {
    _plain.emit('marry', 100, 200);

    // 再过一秒再执行依次
    setTimeout(() => {
        _plain.emit('marry', 1000, 2000);
    }, 1000);
}, 1000);

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/web/1322877.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-12
下一篇 2022-06-12

发表评论

登录后才能评论

评论列表(0条)

保存