1. 中介者模式

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

1.1中介者模式的例子

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

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

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

  1. function Player(name){
  2. this.name=name;
  3. this.enemy=null;
  4. }
  5.  
  6. Player.prototype.win=function(){
  7. console.log(this.name+'won');
  8. };
  9. Player.prototype.lose=function(){
  10. console.log(this.name+'lose');
  11. };
  12. Player.prototype.die=function(){
  13. console.log(this.name+'die');
  14. };

接下来创建两个玩家

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

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

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

var players=[];

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

  1. function Player(name,teamColor){
  2. this.partners=[];
  3. this.enemies=[];
  4. this.state='live';
  5. this.name=name;
  6. this.teamColor=teamColor;
  7. }

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

  1. Player.prototype.win=function(){
  2. console.log('winner:'+this.name);
  3. };
  4. Player.prototype.lose=function(){
  5. console.log('loser:'+this.name);
  6. };

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

  1. Player.prototype.die=function(){
  2. var all_dead=true;
  3. this.state='dead';
  4. for(var i=0,partner;partner=this.partners[i++];){
  5. if(partner.state!='dead'){
  6. all_dead=false;
  7. break;
  8. }
  9. }
  10. if(all_dead === true){
  11. this.lose();
  12. for(var i=0,partner;partner=this.partners[i++];){
  13. partner.lose();
  14. }
  15. for(var i=0,enemy;enemy=this.enemies[i++];){
  16. enemy.win();
  17. }
  18. }
  19. };

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

  1. var playerFactory=function(name,teamColor){
  2. var newPlayer=new Player(name,teamColor);//创建新玩家
  3. for(var i=0,player;player=players[i++];){//通知所有玩家,新玩家加入
  4. if(player.teamColor === newPlayer.teamColor){//队友加入
  5. player.partners.push(newPlayer);
  6. newPlayer.partners.push(player);
  7. }else{
  8. player.enemies.push(newPlayer);
  9. newPlayer.enemies.push(player);
  10. }
  11. }
  12. players.push(newPlayer);
  13. return newPlayer;
  14. };

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

  1. var player1=playerFactory('p1','red');
  2. var player2=playerFactory('p2','red');
  3. var player3=playerFactory('p3','red');
  4. var player4=playerFactory('p4','red');
  5.  
  6. var player5=playerFactory('p5','blue');
  7. var player6=playerFactory('p6','blue');
  8. var player7=playerFactory('p7','blue');
  9. var player8=playerFactory('p8','blue');

让红队全部死亡

  1. player1.die();
  2. player2.die();
  3. player3.die();
  4. player4.die();

此时蓝队玩家胜利

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

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

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

  1. function Player(name,teamColor){
  2. this.name=name;
  3. this.teamColor=teamColor;
  4. this.state=state;
  5. };
  6.  
  7. Player.prototype.win=function(){
  8. console.log(this.name+'won');
  9. };
  10. Player.prototype.lose=function(){
  11. console.log(this.name+'lost');
  12. };
  1. //玩家死亡时
  2. Player.prototype.die=function(){
  3. this.state='dead';
  4. playerDirector.ReceiveMessage('playerDead',this);
  5. };
  6. //移除玩家
  7. Player.prototype.remove=function(){
  8. playerDirector.ReceiveMessage('removePlayer',this);
  9. };
  10. //玩家换队
  11. Player.prototype.changeTeam=function(color){
  12. playerDirector.ReceiveMessage('changeTeam',this,color);
  13. };

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

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

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

  1. var playerDirector=(function(){
  2. var players={},//保存所有玩家
  3. operations={};//中介者可以执行的操作
  4.  
  5. //新增一个玩家
  6. operations.addPlayer=function(player){
  7. var teamColor=player.teamColor
  8. //如果该颜色的玩家还没有成立队伍,则新成立一个队伍
  9. players[teamColor]=players[teamColor]||[];
  10. players[teamColor].push(player);//添加玩家进队伍
  11. };
  12.  
  13. //移除一个玩家
  14. operations.removePlayer=function(player){
  15. var teamColor=player.teamColor,
  16. teamPlayers=players[teamColor]||[];//该队伍所有成员
  17. for(var i=teamPlayers.length-1;i>=0;i--){
  18. if(teamPlayers[i]===player{
  19. teamPlayers.splice(i,1);
  20. }
  21. }
  22. };
  23.  
  24. //玩家换队
  25. operations.changeTeam=function(player,newTeamColor){
  26. operations.removePlayer(player);
  27. player.teamColor=newTeamColor;
  28. operations.addPlayer(player);
  29. }
  30.  
  31. //玩家死亡
  32. operations.playerDead=function(player){
  33. var teamColor=player.teamColor,
  34. teamPlayers=players[teamColor];
  35.  
  36. var all_dead=true;
  37.  
  38. for(var i=0,player;player=teamPlayers[i++];){
  39. if(player.state!='dead'){
  40. all_dead=false;
  41. break;
  42. }
  43. }
  44. //如果全部死亡
  45. if(all_dead===true){
  46. for(var i=0,player;player=teamPlayers[i++];){
  47. player.lose();
  48. }
  49.  
  50. for(var color in players){
  51. if(color !== teamColor){
  52. var teamPlayers=players[color];//对手玩家
  53. for(var i=0,player;player=teamPlayers[i++];){
  54. player.win();
  55. }
  56.  
  57. }
  58. }
  59. }
  60. }
  61.  
  62. var ReceiveMessage=function(){
  63. var message=Array.prototype.shift.call(arguments);
  64. operations[message].apply(this,arguments);
  65. };
  66.  
  67. return{
  68. ReceiveMessage:ReceiveMessage
  69. }
  70. })();

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

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

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

《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. boost.asio系列——buffer

    创建buffer 在io操作中,对数据的读写大都是在一个缓冲区上进行的,在asio框架中,可以通过asio::buffer函数创建一个缓冲区来提供数据的读写.buffer函数本身并不申请内存,只是提供 ...

  2. linux系统日志及其rsyslog服务

    日志是系统用来记录系统运行时候的一些相关消息的纯文本文件 /var/log下保存着大量的纯文本日志文件 日志的目的是为了保持相关程序的运行状态,错误消息,为了对系统运行进行错误分析使用 1.内核消息 ...

  3. D3D 练习小框架

    自己练习D3D 程序搭的小框架,记录在这里,将来看到好回顾自己独自摸索的苦逼样子. #pragma once #pragma comment(lib,"d3d9.lib") #pr ...

  4. MySQL 创建函数(Function)

    目标 怎么样MySQL创建数据库功能(Function) 语法 CREATE FUNCTION func_name ( [func_parameter] ) //括号是必须的,參数是可选的 RETUR ...

  5. Java Design Demo -简单的队列-异步多任务队列(java android)

    简单的单线程队列 -- 工作的时候遇到劣质打印机.给打印机发消息,打印机就会打印,如果在打印机还在打印的时候,就 再发消息打印,就会出现消息丢失.所以需要给上一个任务一些处理的间隔时间. 单线程的消息 ...

  6. Spring中的FactoryBean

    从SessionFactory说起: 在使用SSH集成开发的时候,我们有时候会在applicationContext.xml中配置Hibernate的信息,以下是配置SessionFactory的一段 ...

  7. javascript中外部js文件取得自身完整路径得办法

    原文:javascript中外部js文件取得自身完整路径得办法 有时候我们需要引入一个外部js文件,这个js文件又需要用到自己的路径或者是所在的目录,别问怎么又这么变态的需求,开发做久了各种奇葩需求也 ...

  8. Swift - 属性观察者(willSet与didSet)

    属性观察者,类似于触发器.用来监视属性的除初始化之外的属性值变化,当属性值发生改变时可以对此作出响应.有如下特点: 1,不仅可以在属性值改变后触发didSet,也可以在属性值改变前触发willSet. ...

  9. html中的rowspan和colspan

    摘自w3school(http://www.w3school.com.cn/tags/att_td_colspan.asp)colspan 属性规定单元格可横跨的列数.<table border ...

  10. windows程序员进阶系列:《软件调试》之Win32堆的调试支持

    Win32堆的调试支持 为了帮助程序员及时发现堆中的问题,堆管理器提供了以下功能来辅助调试. 1:堆尾检查(Heap Tail Check) HTC,在堆尾添加额外的标记信息,用于检测堆块是否溢出. ...