Javascript设计模式 -> 观察者模式 ( •̀ ω •́ )✧

本文深入解析观察者模式,通过生动的生活实例和代码示例,阐述了观察者模式如何实现模块间解耦,提高代码的可维护性和扩展性。并提供了一个具体的实现案例,展示了观察者模式在实际项目中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

观察者模式( 又叫发布者-订阅者模式 )应该是最常用的模式之一.

在很多语言里都得到大量应用. 包括我们平时接触的dom事件. 也是js和dom之间实现的一种观察者模式.

div.onclick  =  function click (){
   alert ('click');
};

只要订阅了div的click事件. 当点击div的时候, function click就会被触发.

那么到底什么是观察者模式呢. 先看看生活中的观察者模式。

好莱坞有句名言. “不要给我打电话, 我会给你打电话”.* 这句话就解释了一个观察者模式的来龙去脉。 其中“我”是发布者, “你”是订阅者。

再举个例子,我来公司面试的时候,完事之后每个面试官都会对我说:“请留下你的联系方式, 有消息我们会通知你”。 在这里“我”是订阅者, 面试官是发布者。所以我不用每天或者每小时都去询问面试结果, 通讯的主动权掌握在了面试官手上。而我只需要提供一个联系方式。

观察者模式可以很好的实现2个模块之间的解耦。 假如我正在一个团队里开发一个html5游戏. 当游戏开始的时候,需要加载一些图片素材。加载好这些图片之后开始才执行游戏逻辑. 假设这是一个需要多人合作的项目. 我完成了Gamer和Map模块, 而我的同事A写了一个图片加载器loadImage.

loadImage的代码如下

loadImage(imgAry,  function(){
    Map.init();
    Gamer.init();
});

当图片加载好之后, 再渲染地图, 执行游戏逻辑. 嗯, 这个程序运行良好. 突然有一天, 我想起应该给游戏加上声音功能. 我应该让图片加载器添上一行代码.

loadImage(imgAry, function(){
    Map.init();
    Gamer.init();
    Sount.init();
});

可是写这个模块的同事A去了外地旅游. 于是我打电话给他, 喂. 你的loadImage函数在哪, 我能不能改一下, 改了之后有没有副作用. 如你所想, 各种不淡定的事发生了. 如果当初我们能这样写呢:

loadImage.listen('ready', function(){
    Map.init();
});

loadImage.listen('ready', function(){
   Gamer.init();
});

loadImage.listen('ready', function(){
   Sount.init();
});

loadImage完成之后, 它根本不关心将来会发生什么, 因为它的工作已经完成了. 接下来它只要发布一个信号.

loadImage.trigger('ready');

那么监听了loadImage的’ready’事件的对象都会收到通知. 就像上个面试的例子. 面试官根本不关心面试者们收到面试结果后会去哪吃饭. 他只负责把面试者的简历搜集到一起. 当面试结果出来时照着简历上的电话挨个通知.


说了这么多概念, 来一个具体的实现. 实现过程其实很简单. 面试者把简历扔到一个盒子里, 然后面试官在合适的时机拿着盒子里的简历挨个打电话通知结果.

var Events = function () {

    obj = {};

    __this = this;

    listen = function (key, eventfn) {  //把简历扔盒子, key就是联系方式.
        var stack, _ref;  //stack是盒子
        stack = (_ref = obj[key]) != null ? _ref : obj[key] = [];

        return stack.push(eventfn);
    };

    one = function (key, eventfn) {
        remove(key);
        return listen(key, eventfn);
    };

    remove = function (key) {
        var _ref;

        return (_ref = obj[key]) != null ? _ref.length = 0 : void 0;
    };

    trigger = function () {  //面试官打电话通知面试者
        var fn, stack, _i, _len, _ref, key;

        key   = Array.prototype.shift.call(arguments);
        stack = (_ref = obj[key]) != null ? _ref : obj[key] = [];

        for (_i = 0, _len = stack.length; _i < _len; _i++) {
            fn = stack[_i];
            if (fn.apply(__this, arguments) === false) {
                return false;
            }
        }

        return {
            listen : listen,
            one    : one,
            remove : remove,
            trigger: trigger
        }
    };

}

最后用观察者模式来做一个成人电视台的小应用.

//订阅者
var adultTv = Event();

adultTv.listen('play',  function(data){
    alert("今天是谁的电影" + data.name);
});

//发布者
adultTv .trigger('play',  { 'name': '麻生希' })
“你不知道的 javascript 设计模式系列” ~( ̄▽ ̄)~

转载自 AlloyTeam
http://www.alloyteam.com/2012/10/commonly-javascript-design-pattern-observer-mode/


用c++题目描述 有一个 n × m n×m 格的迷宫(表示有 n n 行、 m m 列),其中有可走的也有不可走的,如果用 1 1 表示可以走, 0 0 表示不可以走,文件读入这 n × m n×m 个数据和起始点、结束点(起始点和结束点都是用两个数据来描述的,分别表示这个点的行号和列号)。现在要你编程找出所有可行的道路,要求所走的路中没有重复的点,走时只能是上下左右四个方向。如果一条路都不可行,则输出相应信息(用 − 1 −1 表示无路)。 优先顺序:左上右下。数据保证随机生成。 输入格式 第一行是两个数 n , m ( 1 < m , n < 15 ) n,m(1<m,n<15),接下来是 n n 行 m m 列由 1 1 和 0 0 组成的数据,最后两行是起始点和结束点。 输出格式 所有可行的路径,描述一个点时用 ( x , y ) (x,y) 的形式,除开始点外,其他的都要用 -> 表示方向。 如果没有一条可行的路则输出 − 1 −1。 输入输出样例 输入#1 5 6 1 0 0 1 0 1 1 1 1 1 1 1 0 0 1 1 1 0 1 1 1 1 1 0 1 1 1 0 1 1 1 1 5 6 输出#1 (1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
07-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值