设计模式(发布订阅+观察者)

/*

 * Observer [əbˈzɜːrvər]观察者模式

 * Publish [ˈpʌblɪʃ] & Subscribe [səbˈskraɪb] 发布/订阅模式

 *

 * 设计模式仅仅是“锦上添花”!设计模式是一种思想,基于这种思想可以更好的去管理代码!!

 *   + 单例设计模式

 *   + 工厂设计模式

 *   + 构造函数设计模式

 *   + Promise承诺者设计模式

 *   + 发布/订阅设计模式「自定义事件」

 *   + 观察者设计模式

 *   + ...

 */

 发布订阅

 到达某个时间后,去执行,在Jquery中有发布订阅这一套:

&plan.add添加, fire执行

let $plan = $.Callbacks();

// main.js  页面加载完成后做啥事...
window.addEventListener('load', function () {
    $plan.fire(10, 20);
});

// A.js
(function () {
    const fn1 = function fn1(x, y) {
        console.log('fn1', x, y);
    };
    // ...
    $plan.add(fn1);
})();

// B.js
(function () {
    const fn2 = function fn2() {
        console.log('fn2');
    };
    // ...
    $plan.add(fn2);
})();

// C.js
(function () {
    const fn3 = function fn3() {
        console.log('fn3');
    };
    // ...
    $plan.add(fn3);
})(); 

 自己实现 发布订阅

 1.自定义事件池

 2. on off emit

(function () {
    // 自定义事件池
    let listeners = {};

    // 校验的处理
    const checkName = name => {
        if (typeof name !== "string") throw new TypeError('name is not a string!')
    };
    const checkFunc = func => {
        if (typeof func !== "function") throw new TypeError('func is not a function!')
    };

    // 向事件池中加入方法
    const on = function on(name, func) {
        checkName(name);
        checkFunc(func);
        // 判断事件池中是否存在这个事件
        if (!listeners.hasOwnProperty(name)) listeners[name] = [];
        let arr = listeners[name];
        // 去重处理
        if (arr.indexOf(func) >= 0) return;
        arr.push(func);
    };

    // 从事件池中移除方法
    const off = function off(name, func) {
        checkName(name);
        checkFunc(func);
        let arr = listeners[name];
        if (!arr) return;
        for (let i = 0; i < arr.length; i++) {
            let item = arr[i];
            if (item === func) {
                // 把这一项移除掉:为了避免数据塌陷问题,先赋值为null
                // arr.splice(i, 1);
                arr[i] = null;
                break;
            }
        }
    };

    // 通知指定事件池中的方法执行
    const emit = function emit(name, ...params) {
        checkName(name);
        let arr = listeners[name];
        if (!arr) return;
        // 通知集合中的每个方法执行
        for (let i = 0; i < arr.length; i++) {
            let item = arr[i];
            if (item === null) {
                // 此时把为null项从集合中移除掉
                arr.splice(i, 1);
                i--;
                continue;
            }
            item(...params);
        }
    };

    // 暴露API
    window.$sub = {
        on,
        off,
        emit
    };
})();

/* 测试 */
setTimeout(() => {
    $sub.emit('AA', 10, 20);

    setTimeout(() => {
        $sub.emit('AA', 100, 200);
    }, 2000);
}, 2000);

const fn1 = (x, y) => {
    console.log('fn1', x, y);
};
const fn2 = (x, y) => {
    console.log('fn2', x, y);
    // 第一次执行到FN2的时候,从事件池中移除FN1/FN2
    $sub.off('AA', fn1);
    $sub.off('AA', fn2);
};
const fn3 = () => console.log('fn3');
const fn4 = () => console.log('fn4');
const fn5 = () => console.log('fn5');
const fn6 = () => console.log('fn6');
$sub.on('AA', fn1);
$sub.on('AA', fn2);
$sub.on('AA', fn3);
$sub.on('AA', fn2);
$sub.on('AA', fn3);
$sub.on('AA', fn4);
$sub.on('AA', fn5);
$sub.on('AA', fn6);
$sub.on('BB', fn1);
$sub.on('BB', fn2);

面向对象思想的发布订阅

(function () {
    class Sub {
        // 定义实例的私有事件池
        listeners = []; //0x000

        // 定义原型上通用的方法
        add(func) {
            if (typeof func !== "function") throw new TypeError("function is not a function!");
            let { listeners } = this;
            if (listeners.includes(func)) return;
            listeners.push(func);
        }
        remove(func) {
            if (typeof func !== "function") throw new TypeError("function is not a function!");
            let { listeners } = this;
            this.listeners = listeners.map(item => {
                if (item === func) return null;
                return item;
            });
        }
        fire(...params) {
            let { listeners } = this;
            for (let i = 0; i < listeners.length; i++) {
                let item = listeners[i];
                if (item === null) {
                    listeners.splice(i, 1);
                    i--;
                    continue;
                }
                item(...params);
            }
        }
    }

    /* 暴露API */
    if (typeof window !== "undefined") window.Sub = Sub;
    if (typeof module === "object" && typeof module.exports === "object") module.exports = Sub;
})();

/* 测试 */
setTimeout(() => {
    s1.fire(10, 20);

    setTimeout(() => {
        s2.fire(100, 200);
    }, 2000);
}, 2000);

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');

let s1 = new Sub;
s1.add(fn1);
s1.add(fn2);
s1.add(fn3);
s1.add(fn4);
s1.add(fn5);
s1.add(fn6);

let s2 = new Sub;
s2.add(fn4);
s2.add(fn5);
s2.add(fn6);

观察者模式

观察者和目标

观察者:具备update,通知时把每个观察中的update方法执行

目标:为了订阅和通知方法去执行

思路:

 

 

class Subject {
    observerList = [];

    // 校验观察者的格式
    checkObserver(observer) {
        if (observer !== null && /^(object|function)$/.test(typeof observer)) {
            if (typeof observer.update === "function") {
                return true;
            }
        }
        throw new TypeError("Illegal observer");
    }
    add(observer) {
        this.checkObserver(observer);
        let { observerList } = this;
        if (observerList.includes(observer)) return;
        observerList.push(observer);
    }
    remove(observer) {
        this.checkObserver(observer);
        let { observerList } = this;
        this.observerList = observerList.map(item => {
            if (item === observer) return null;
            return item;
        });
    }
    notify(...params) {
        let { observerList } = this;
        for (let i = 0; i < observerList.length; i++) {
            let item = observerList[i];
            if (item === null) {
                observerList.splice(i, 1);
                i--;
                continue;
            }
            item.update(...params);
        }
    }
}

// 定义多个观察者
let observer1 = {
    update(...params) {
        console.log('我是观察者1:', params);
    }
};

class Observer {
    update(...params) {
        console.log('我是观察者2:', params);
    }
}

const sub = new Subject;
sub.add(observer1);
sub.add(new Observer);

setTimeout(() => {
    sub.notify(100, 200);
}, 2000);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值