1. 中介者模式

中介者模式的作用就是用来解除对象与对象之间的紧耦合关系,增加中介者后,所有相关对象都通过中介者来通信,而不再相互引用

1.1中介者模式的例子

以泡泡堂游戏为例,先定义一个玩家构造函数,它有三个原型方法

Player.prototype.win,Player.prototype.lose,Player.prototype.die

当只有两个玩家时,一个玩家死亡时游戏结束,同时通知他的对手胜利

function Player(name){
this.name=name;
this.enemy=null;
} Player.prototype.win=function(){
console.log(this.name+'won');
};
Player.prototype.lose=function(){
console.log(this.name+'lose');
};
Player.prototype.die=function(){
console.log(this.name+'die');
};

接下来创建两个玩家

var player1=new Player('玩家1');
var player2=new Player('玩家2');
//设置敌人
player1.enemy=player2;
player2.enemy=player1;
//玩家1死亡时,调用自己的die方法完成一局游戏
player1.die();

当玩家增加时,每个玩家有了自己的队友和若干敌人

定义一个数组players保存所有的玩家,创建玩家之后,循环players来给每个玩家设置敌人和队友

var players=[];

再改写构造函数Player,使每个玩家对象都增加一些属性,分别是队友列表、敌人列表、玩家当前状态、角色名字以及玩家所在队伍的颜色

function Player(name,teamColor){
this.partners=[];
this.enemies=[];
this.state='live';
this.name=name;
this.teamColor=teamColor;
}

胜利和失败后,对每个玩家提示结果

Player.prototype.win=function(){
console.log('winner:'+this.name);
};
Player.prototype.lose=function(){
console.log('loser:'+this.name);
};

玩家死亡时,需要遍历其他队友的状况,如果队友全部死亡,这局游戏失败,同时敌人所有玩家胜利

Player.prototype.die=function(){
var all_dead=true;
this.state='dead';
for(var i=0,partner;partner=this.partners[i++];){
if(partner.state!='dead'){
all_dead=false;
break;
}
}
if(all_dead === true){
this.lose();
for(var i=0,partner;partner=this.partners[i++];){
partner.lose();
}
for(var i=0,enemy;enemy=this.enemies[i++];){
enemy.win();
}
}
};

最后定义一个工厂来创建玩家

var playerFactory=function(name,teamColor){
var newPlayer=new Player(name,teamColor);//创建新玩家
for(var i=0,player;player=players[i++];){//通知所有玩家,新玩家加入
if(player.teamColor === newPlayer.teamColor){//队友加入
player.partners.push(newPlayer);
newPlayer.partners.push(player);
}else{
player.enemies.push(newPlayer);
newPlayer.enemies.push(player);
}
}
players.push(newPlayer);
return newPlayer;
};

用这段代码来创建8个玩家,分属红蓝两队

var player1=playerFactory('p1','red');
var player2=playerFactory('p2','red');
var player3=playerFactory('p3','red');
var player4=playerFactory('p4','red'); var player5=playerFactory('p5','blue');
var player6=playerFactory('p6','blue');
var player7=playerFactory('p7','blue');
var player8=playerFactory('p8','blue');

让红队全部死亡

player1.die();
player2.die();
player3.die();
player4.die();

此时蓝队玩家胜利

1.2 用中介者模式改造上述示例

上述示例中,每个玩家和其他玩家都是紧耦合在一起,partners,enemies保存着其他玩家对象的引用。当对象状态改变,如死亡时,必须显示遍历通知其他玩家

首先仍然是定义Player构造函数和player对象的原型方法

function Player(name,teamColor){
this.name=name;
this.teamColor=teamColor;
this.state=state;
}; Player.prototype.win=function(){
console.log(this.name+'won');
};
Player.prototype.lose=function(){
console.log(this.name+'lost');
};
//玩家死亡时
Player.prototype.die=function(){
this.state='dead';
playerDirector.ReceiveMessage('playerDead',this);
};
//移除玩家
Player.prototype.remove=function(){
playerDirector.ReceiveMessage('removePlayer',this);
};
//玩家换队
Player.prototype.changeTeam=function(color){
playerDirector.ReceiveMessage('changeTeam',this,color);
};

改写创建玩家对象的工厂函数

var playerFactory=function(name,teamColor){
var newPlayer=new Player(name,teamColor);
playerDirector.ReceiveMessage('addPlayer',newPlayer);
return newPlayer;
};

playerDirector开放一个对外暴露的接口ReceiveMessage,负责接收player对象发送的消息,
而player对象发送的时候,总是把自身this作为参数发送给playDirector,以便playerDirector识别消息来自于哪个玩家对象

var playerDirector=(function(){
var players={},//保存所有玩家
operations={};//中介者可以执行的操作 //新增一个玩家
operations.addPlayer=function(player){
var teamColor=player.teamColor
//如果该颜色的玩家还没有成立队伍,则新成立一个队伍
players[teamColor]=players[teamColor]||[];
players[teamColor].push(player);//添加玩家进队伍
}; //移除一个玩家
operations.removePlayer=function(player){
var teamColor=player.teamColor,
teamPlayers=players[teamColor]||[];//该队伍所有成员
for(var i=teamPlayers.length-1;i>=0;i--){
if(teamPlayers[i]===player{
teamPlayers.splice(i,1);
}
}
}; //玩家换队
operations.changeTeam=function(player,newTeamColor){
operations.removePlayer(player);
player.teamColor=newTeamColor;
operations.addPlayer(player);
} //玩家死亡
operations.playerDead=function(player){
var teamColor=player.teamColor,
teamPlayers=players[teamColor]; var all_dead=true; for(var i=0,player;player=teamPlayers[i++];){
if(player.state!='dead'){
all_dead=false;
break;
}
}
//如果全部死亡
if(all_dead===true){
for(var i=0,player;player=teamPlayers[i++];){
player.lose();
} for(var color in players){
if(color !== teamColor){
var teamPlayers=players[color];//对手玩家
for(var i=0,player;player=teamPlayers[i++];){
player.win();
} }
}
}
} var ReceiveMessage=function(){
var message=Array.prototype.shift.call(arguments);
operations[message].apply(this,arguments);
}; return{
ReceiveMessage:ReceiveMessage
}
})();

现在除了中介者本身,没有一个玩家知道其他玩家的存在,玩家与玩家之间的耦合关系已经解除

某个玩家的任何操作不需要通知其他买家,只需要给中介者发送一个消息

中介者处理完消息之后,把处理结果反馈给其他玩家

《JavaScript设计模式与开发实践》读书笔记之中介者模式的更多相关文章

  1. JavaScript设计模式与开发实践——读书笔记1.高阶函数(上)

    说来惭愧,4个多月未更新了.4月份以后就开始忙起来了,论文.毕设.毕业旅行等七七八八的事情占据了很多时间,毕业之后开始忙碌的工作,这期间一直想写博客,但是一直没能静下心写.这段时间在看<Java ...

  2. JavaScript设计模式与开发实践——读书笔记1.高阶函数(下)

    上部分主要介绍高阶函数的常见形式,本部分将着重介绍高阶函数的高级应用. 1.currying currying指的是函数柯里化,又称部分求值.一个currying的函数会先接受一些参数,但不立即求值, ...

  3. Javascript设计模式与开发实践读书笔记(1-3章)

    第一章 面向对象的Javascript 1.1 多态在面向对象设计中的应用   多态最根本好处在于,你不必询问对象“你是什么类型”而后根据得到的答案调用对象的某个行为--你只管调用行为就好,剩下的一切 ...

  4. javascript设计模式与开发实践阅读笔记(8)——观察者模式

    发布-订阅模式,也叫观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 在JavaScript开发中,我们一般用事件模型来替代传统的观察者模式. ...

  5. javascript设计模式与开发实践阅读笔记(7)——迭代器模式

    迭代器模式:指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺 ...

  6. javascript设计模式与开发实践阅读笔记(6)——代理模式

    代理模式:是为一个对象提供一个代用品或占位符,以便控制对它的访问. 代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对 ...

  7. javascript设计模式与开发实践阅读笔记(4)——单例模式

    定义 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 具体来说,就是保证有些对象有且只有一个,比如线程池.全局缓存.浏览器中的window 对象等.在js中单例模式用途很广,比如登录 ...

  8. 《JavaScript设计模式与开发实践》笔记第八章 发布-订阅模式

    第八章 发布-订阅模式 发布-订阅模式描述 发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 发布-订阅模式可以广泛应用于 ...

  9. 《JavaScript设计模式与开发实践》笔记第一章

    第一章 面向对象的JavaScript 动态类型语言和鸭子类型 编程语言按照数据类型大体可以分为两类:静态类型语言.动态类型语言. 静态类型语言:在编译时便已确定变量的类型. 优点: 在编译时就能发现 ...

  10. javascript设计模式与开发实践阅读笔记(5)——策略模式

    策略模式:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换. 我的理解就是把各种方法封装成函数,同时存在一个可以调用这些方法的公共函数.这样做的好处是可以消化掉内部的分支判断,使代码效率 ...

随机推荐

  1. vs2012 不显示最近项目

    visual studio起始页不显示最近使用项目的解决办法方法一 1.开始 → 运行 → 输入 regedit 回车,打开注册表编辑器. 2.定位到 HKEY_CURRENT_USER/Softwa ...

  2. jvm常用参数设置 good

    1.堆的大小可以通过 -Xms 和 -Xmx 来设置,一般将他们设置为相同的大小,目的是避免在每次垃圾回收后重新调整堆的大小,比如 -Xms=2g -Xmx=2g 或者 -Xms=512m -Xmx= ...

  3. 关于wind7重新安装系统后,连接mysql的问题

    系统重装对于我们来说,可以说是家常便饭了.但重装系统之后 ,又要装很多的应用软件是会很烦的.特别是重装一些数据库软件,时间长不说,搞不好数据丢失了会让人抓狂. 今天我简单介绍一个不用重装mysql的方 ...

  4. 尺度空间(Scale space)理论

    尺度空间方法的基本思想是:在视觉信息处理模型中引入一个被视为尺度的參数,通过连续变化尺度參数获得不同尺度下的视觉处理信息,然后综合这些信息以深入地挖掘图像的本质特征.尺度空间方法将传统的单尺度视觉信息 ...

  5. qt宽字符串中文乱码(codec->toUnicode值得学习)

    乱码原因: QT使用的是utf-8 简体中文版的windows操作系统及其应用软件默认都是ANSI/GBK编码.而且这里应该是宽字符串. 多字节ANISGB 宽字符UNICODE 多字节显示标准字符的 ...

  6. POJ 3007 Organize Your Train part II

    题意: 如上图所示,将一个字符串进行分割,反转等操作后不同字符串的个数: 例如字符串abba:可以按三种比例分割:1:3:2:2:3:1 部分反转可以得到如下所有的字符串: 去掉重复可以得到六个不同的 ...

  7. Android开发之搜Ya项目说明(3)

    项目 搜芽移动client ----seller,app,base三个包的简单说明 作者 曾金龙 Tel:18664312687 QQ :470910357@qq.com 时间 2014-10-14 ...

  8. Android平均分布的布局图像的下一行

    Android下一行平均分布图片的布局 这是一个非经常见的需求,比方有三个图片button,须要在底部三个平均,比方下个样例: 下面是布局文件 <LinearLayout android:lay ...

  9. Swift - 访问控制(private,internal,public)

    在Swift语言中,访问修饰符有三种,分别为private,internal和public.同时,Swift对于访问权限的控制,不是基于类的,而是基于文件的.其区别如下: 1,private priv ...

  10. Indy的TCPServer到底能支持多少个连接

    最近一个项目,最开始使用IdTcpServer,在大压力测试的时候,只连接了800个多一点的客户端(每个客户端连接上之后每秒钟发送一个几十字节的报文,服务器应答).但是持续的时间不会超过10分钟,服务 ...