var publisher = {

    // 订阅者数组
subscribers : {
"any" : []
}, // 增加订阅者
on : function(type, fn, context){
var subscribers = this.subscribers;
type = type || "any";
context = context || this;
fn = typeof fn === "function" ? fn : context[fn];
if(!subscribers[type]){
subscribers[type] = [];
}
subscribers[type].push({"fn" : fn, "context" : context});
}, // 移除订阅者
off : function(type, fn, context){
this.visit("unPublish", type, fn, context)
}, // 通知
fire : function(type, arg){
this.visit("publish", type, arg);
}, // 访问订阅者数组
visit : function(action, type, arg, context){
var subscribers, i, len;
type = type || "any";
subscribers = this.subscribers[type];
len = subscribers.length || 0; switch(action){
case "publish" :
for(i = 0; i < len; i++){
subscribers[i].fn.call(subscribers[i].context, arg);
}
break;
case "unPublish":
for(i = 0; i < len; i++){
if(subscribers[i].fn === arg && subscribers[i].context === context){
subscribers.splice(i, 1);
}
}
break;
}
}
}; function makePublisher(o){
o.subscribers = {"any" : []};
for(var p in publisher ){
if(publisher.hasOwnProperty(p) && typeof publisher[p] === "function"){
o[p] = publisher[p];
}
}
return o;
} // 发布者Play
// 发布两个事件:1、有玩家加入 2、玩家开始玩
function Player(name, key){
this.point = 0;
this.name = name;
this.key = key;
this.fire("add", this);
} Player.prototype.play = function(){
this.point += 1;
this.fire("play", this);
}; // 观察者/订阅者 game,观察2个事件:1、有玩家加入 2、玩家开始玩
// 同时作为发布者game,通知积分榜更新
var game = {
// 存储对象和按键key的关系
keys : {},
// 订阅
addPlayer : function(player){
this.keys[player.key] = player;
}, // 通知订阅者scoreboard更新
handlyPlay : function(){
var score = {}, keys = this.keys, p;
for(p in keys){
if(keys.hasOwnProperty(p)){
score[keys[p].name] = keys[p].point;
}
}
this.fire("update", score);
}, // 封装keypress事件
keydown : function(e){
var which, code;
e = e || event;
which = e.which || e.keyCode;
code = String.fromCharCode(which);
if(this.keys[code]){
this.keys[code].play();
}
}
}; // 积分榜
var scoreboard = {
dom : document.getElementById("score_board"), // 更新积分榜 参数格式 {playname1 : point, playname2 : point }
update : function(score){
var p, html = "";
for(p in score){
if(score.hasOwnProperty(p)){
html += p + "获得了" + score[p] + "<br/>";
}
}
this.dom.innerHTML = html;
}
}; // Player作为发布者,因其需要通知订阅者game新增玩家以及玩家积分变化
// game对Player而言是订阅者,因其需要订阅Player的特定活动add(新增玩家)和play(玩家积分发生变化)
// game对scoreboard而言是发布者,因其在观察到Player的play事件之后需要通知scoreboard更新积分
makePublisher(Player.prototype);
makePublisher(game); Player.prototype.on("add", game.addPlayer, game);
Player.prototype.on("play", game.handlyPlay, game);
game.on("update", scoreboard.update, scoreboard); //excute
while(true){
var name = prompt("say your name, man"), key;
if(name && name !== "null"){
while(true){
key = prompt("what is your key");
if(key && key !== "null"){
break;
}
alert("亲,还是指定个key吧,不然你没办法玩的,相信我");
}
new Player(name, key);
}
else {
break;
}
} document.onkeydown = function(e){
game.keydown.call(game, e);
};

Javascript模式(二) 发布者/订阅者模式的更多相关文章

  1. JavaScript 设计模式: 发布者-订阅者模式

    JavaScript 设计模式: 发布者-订阅者模式 发布者-订阅者模式 https://github.com/Kelichao/javascript.basics/issues/22 https:/ ...

  2. vue双向绑定(数据劫持+发布者-订阅者模式)

    参考文献:https://www.cnblogs.com/libin-1/p/6893712.html 实现mvvm主要包含两个方面,数据变化更新视图,视图变化更新数据. 关键点在于data如何更新v ...

  3. EventBus事件总线框架(发布者/订阅者模式,观察者模式)

    一. android应用内消息传递的方式: 1. handler方式-----------------不同线程间传递消息. 2. Interface接口回调方式-------任意两个对象. 3. In ...

  4. C#事件支持发布者/订阅者模式(观察者模式)

    C#事件支持发布者/订阅者模式,发布者将事件通知给订阅者,而订阅者在事件发生时调用已经注册好的事件处理函数.        public delegate void delUpdate();  //委 ...

  5. 学习javascript设计模式之发布-订阅(观察者)模式

    1.发布-订阅模式又叫观察者模式,它定义对象之间一种一对多的依赖关系. 2.如何实现发布-订阅模式 2-1.首先指定好发布者 2-2.给发布者添加一个缓冲列表,用户存放回调函数以便通知订阅者 2-3. ...

  6. 用原生javascript实现最简单的发布者-订阅者模式

    http://www.cnblogs.com/surahe/p/6065778.html 发布—订阅模式可以广泛应用于异步编程中,这是一种替代传递回调函数的方案.比如,我们可以订阅 ajax 请求的 ...

  7. 发布者订阅者模式之JAVA实现

        1.发布者接口 package com.shoshana.publishsubscribe; public interface IPublisher<M> { public voi ...

  8. js中的观察者模式与发布者/订阅者模式的区别?

  9. .netcore利用DI实现订阅者模式 - xms

    结合DI,实现发布者与订阅者的解耦,属于本次事务的对象主体不应定义为订阅者,因为订阅者不应与发布者产生任何关联 一.发布者订阅者模式 发布者发出一个事件主题,一个或多个订阅者接收这个事件,中间通过事件 ...

随机推荐

  1. windows 批处理删除指定目录下 指定类型 指定天数之前文件

    删除D:\test下5天前所有文件,如下: @echo offset SrcDir=D:\testset DaysAgo=5forfiles /p %SrcDir% /s /m *.* /d -%Da ...

  2. Vue中slot内容分发

    <slot>元素是一个内容分发API,使用多个内容插槽时可指定name属性 <!DOCTYPE html> <html> <head> <meta ...

  3. nodeJS(2)深了解: nodeJS 项目架构详解(app.js + Express + Http)

    简略了解:nodeJS 深了解(1): Node.js + Express 构建网站预备知识 环境: 环境: win7 + nodeJS 版本(node): 新建 nodeJS 项目: 名称为: te ...

  4. updatepanel中使用alert弹出框方法

    原文发布时间为:2009-05-17 -- 来源于本人的百度文章 [由搬家工具导入]         ScriptManager.RegisterStartupScript(this.UpdatePa ...

  5. Ajax 控件 的使用 以及js调用后台方法【自己总结一下】

    原文发布时间为:2009-05-16 -- 来源于本人的百度文章 [由搬家工具导入] 源码:http://download.csdn.net/source/1340120   (js调用后台方法只在源 ...

  6. 牛客挑战赛14-F细胞

    https://www.nowcoder.com/acm/contest/81/F 循环卷积的裸题,太久没做FFT了,这么裸的循环卷积都看不出来 注意一下本文的mod 都是指表示幂的模数,而不是NTT ...

  7. OpenGL ES 画直线代码实例

    http://blog.csdn.net/yexiaozi_007/article/details/7978620 以画xyz坐标轴为例,很多人会遇到用glcolor设置了颜色,但是直线画出来还是黑色 ...

  8. android的布局-----RelativeLayout(相对布局)

    学习导图 注:父容器定位的属性值只能是Boolean ,兄弟组件定位的属性值只能是ID 典型案例(梅花) <?xml version="1.0" encoding=" ...

  9. vim技巧记录底行模式的使用(1)

    若正在编辑文件,临时须要查看目录: (1)直接在底行模式下使用ls命令,完整的为:!ls 在我这里就显示如下的结果: functionpointer    helloWorld.s       tes ...

  10. 查询/删除/建立DB2数据表的主键

    一.查询表主键. describe indexes for table <instancename>.<tablename> 例: describe indexes for t ...