[分享]javascript中的观察者模式实现.顺便散分...

猿敲月下码 2012-06-01 05:01:43
比如有这样一个场景,一款游戏玩家在等级1~10之间可以领取3000点经验,等级11级以上可以领取2000点经验.

我们可以用观察者模式来实现这个需求.

这里玩家就是一个观察者,或者说是一个订阅者,游戏系统就是一个被观察者,或者说一个发送者

下面用代码来实现:

<script type="text/javascript">
// 经验系统
var Experience = function(param) {
this.name = param.name;
// 经验值
this.expVal = param.expVal;
this.players = [];
}
// 发放经验
Experience.prototype.giveExp = function(player) {
console.log("系统送给[" + player.name + "]" + this.expVal + "点经验.");
}

// 玩家
var Player = function(param) {
this.name = param.name;
}

// 申请经验模式
Player.prototype.apply = function(experience) {
var players = experience.players;
var isExist = false;
for(var i=0,len=players.length;i<len;i++) {
if(players[i] == this) {
isExist = true;
break;
}
}

if(!isExist) {
players.push(this);
}

return this;
}
// 领取经验
Player.prototype.getExp = function(experience) {
var players = experience.players;
for(var i=0,len=players.length;i<len;i++) {
if(players[i] == this) {
experience.giveExp(this);
break;
}
}

return this;
}



// 测试

// 申明玩家
var player1 = new Player({"name":"张三"}); // 玩家1,等级4
var player2 = new Player({"name":"李四"}); // 玩家2,等级12

// 申明经验系统
var exp2000 = new Experience({name:"2000点经验",expVal:2000});
var exp3000 = new Experience({name:"3000点经验",expVal:3000});

// 等级1~10能申请3000点经验
player1.apply(exp3000);
// 等级11以上能申请2000点经验
player2.apply(exp2000);

// 去NPC处领取经验:
player1.getExp(exp3000);
player2.getExp(exp2000);

/*
输出:
系统送给[张三]3000点经验.
系统送给[李四]2000点经验.
*/
</script>


观察者模式又被成为发布者-订阅者模式,鲜明的例子就是报纸的投放
订阅者订阅一种报纸,报社出版报纸.
订阅者负责接收数据(报纸),报社负责发送数据
订阅者接收到报纸之后可以做一些列操作比如裁剪报纸,拿去上厕所....这些事情可以看成一个回调方法

可以看出订阅者跟报社是相互独立开的. 这样的好处运用在项目上有利于代码的维护

订阅者和报社的例子可以看这里



不知道说清楚了没..
...全文
349 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
猿敲月下码 2012-06-05
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 的回复:]

1. 不好意思,是我漏看了循环中的if。
JScript code

if(players[i] == this) {
experience.giveExp(this);
break;
}


2. 没有听说过“推”和“拉”的区别,去查了一下。下面这些引自这儿:


Push model. In the push model, the client sends all……
[/Quote]

学习了. 多谢指点.
panghuhu250 2012-06-05
  • 打赏
  • 举报
回复
1. 不好意思,是我漏看了循环中的if。
  
if(players[i] == this) {
experience.giveExp(this);
break;
}


2. 没有听说过“推”和“拉”的区别,去查了一下。下面这些引自这儿:


Push model. In the push model, the client sends all relevant information regarding the state change to the subject, which passes the information on to each observer.

Pull model. In the pull model, the client notifies the subject of a state change. After the observers receive notification, they access the subject or the client for additional data (see Figure 5) by using a getState() method.

可见,无论是“推”还是“拉”,都是以被观察者发出更新通知开始,两者的区别在于“推”模式中,通知中包括了所有更新的信息(不管用户需要多少),而“拉”模式中,只是通知有更新啦,然后订户自己来拿他需要的。

用你的报亭的比喻,“推”相当于送货上门,“拉”相当于电话通知,而原帖中的实现相当于用户自己不时去问(这是观察者模式要避免的)。
猿敲月下码 2012-06-04
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]
1. 程序有bug,现在的设计使得每一个player领取经验时,都会给同组的人再发一遍经验。而且player想领经验就领经验。

2. 观察者模式是观察者订阅,被观察者在适当的时候通知观察者(调用观察者订阅时注册的函数),这样避免了观察者不停的检测被观察者的状态。所以上面这个函数应该是Experience的,它在适当的时刻(比如新的一天开始时),给所有在它这儿注册的player发放经验(所以函数名字应该叫giveExperience)。
[/Quote]

谢谢您的意见.我看了下,对于第一点:
// 去NPC处领取经验:
player1.getExp(exp3000);
//player2.getExp(exp2000);
把第二行注释掉就打印"系统送给[张三]3000点经验." 好像没有你所说的都会给同组的人再发一遍经验

对于第二点,我想你的意思应该是观察者模式中的"推"和"拉"

比如说订购报纸分两种情况:一种是订阅者主动去报刊亭拿报纸(拉),一种是邮递员把报纸送到家里(推)

而我这里做的就是自己去拿报纸.. 当然换成"推"的形式也是可以的

现在的需求改成:每天12点系统会定时发放经验

新增一个函数:
// 定时发放经验
Experience.prototype.giveExperience = function() {
for(var i=0,len=this.players.length;i<len;i++) {
var player = this.players[i];
console.log("系统送给[" + player.name + "]" + this.expVal + "点经验.");
}
}


测试:

// 定时发放经验:
exp3000.giveExperience();
exp2000.giveExperience();

/*
输出:
系统送给[张三]3000点经验.
系统送给[李四]2000点经验.
*/

licip 2012-06-02
  • 打赏
  • 举报
回复
收藏了,谢谢了。
chate 2012-06-02
  • 打赏
  • 举报
回复
高手云集啊!
panghuhu250 2012-06-01
  • 打赏
  • 举报
回复
[Quote=引用楼主 的回复:]
// 领取经验
Player.prototype.getExp = function(experience) {
var players = experience.players;
for(var i=0,len=players.length;i<len;i++) {
if(players[i] == this) {
experience.giveExp(this);
break;
}
}

return this;
}
[/Quote]

这个有问题。

1. 程序有bug,现在的设计使得每一个player领取经验时,都会给同组的人再发一遍经验。而且player想领经验就领经验。

2. 观察者模式是观察者订阅,被观察者在适当的时候通知观察者(调用观察者订阅时注册的函数),这样避免了观察者不停的检测被观察者的状态。所以上面这个函数应该是Experience的,它在适当的时刻(比如新的一天开始时),给所有在它这儿注册的player发放经验(所以函数名字应该叫giveExperience)。
jiestyle21 2012-06-01
  • 打赏
  • 举报
回复
好东西,谢谢分享!收藏了~
soars 2012-06-01
  • 打赏
  • 举报
回复
感谢经验分享!
猿敲月下码 2012-06-01
  • 打赏
  • 举报
回复
谢谢围观...
乌镇程序员 2012-06-01
  • 打赏
  • 举报
回复
收藏了。
三石-gary 2012-06-01
  • 打赏
  • 举报
回复
thanks for sharing

87,979

社区成员

发帖
与我相关
我的任务
社区描述
Web 开发 JavaScript
社区管理员
  • JavaScript
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧