【学习笔记javascript设计模式与开发实践(中介者模式)----14】

第14章 中介者模式

中介者模式的作用就是解除对象与对象之间的紧耦合关系。增加一个中介者对象后,所有的相关对象通过中介者对象来通信,而不是互相引用,所以当一个对象发生改变时,只需要通知中介者对象即可。中介者使各对象之间耦合松散,而且可以独立地改变他们之间的交互。中介者模式使网状的多对多关系变成了相对简单的一对多关系。

 

 

如上图A发生改变,则需要同时通知跟A发生引用关系的BCDEF这4个对象,而使用中介者模式之后,A发生改变时则只需要通知这个中介者对象即可

 

14.1 现实中的中介者

1.       机场指挥塔

2.       博彩公司

14.2 中介者模式的例子----泡泡游戏

大家可能都还记得泡泡堂游戏,作者曾经写过一个,在游戏之初只支持两个玩家同时进行对战。

先定义一个玩家构造函数,它有3个简单的原型方法Play.prototype.win、Play.prototype.lose、Play.prototype.die

因为玩家数目是2个,所以当其中一个玩家死亡的时候游戏便结束,同时通知它的对手胜利。

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+'lost');
}

Player.prototype.die=function(){
   this.lose();
   this.enemy.win();
}

接下来创建2个玩家

var player1 = new Player(‘皮蛋’);
var player2 = new Player(‘小乖’);

给玩家相互设置敌人

player1.enemy = player2;
player2.enemy = player1;

当玩家player1被泡泡炸死的时候,只需要调用这一句代码便完成了一局游戏

player1.die();

后来觉得2人玩没有意思,真正的泡泡堂游戏至多可以有8个玩家,并分成红蓝两队进行游戏。

 

14.2.1 为游戏增加队伍

现在我们改进一下游戏。因为玩家数量变多,用下面的方式来设置队友和敌人无疑很低效。

player1.partners = [player1, player2, player3,player4];
player1.enemies = [player5, player6, player7,player8];
 .
 .
 .
player5.partners = [player5, player,6, player7,player8];
player5.enemies = [player1, player2, player3,player4];

所以我们定义一个数组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.prototye.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;emeny = this.enemies[i++];){
   enemy.win();
}
   }
}

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

var playerFactory=function(name,teamColor){
    var newPlayer=newPlayer(name,teamColor);
    for(vari=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(newPlayer);
       }
    }
    players.push(newPlayer);
    return newPlayer;
}

现在来感受一下,用这段代码创建8个玩家:

//红队

var plaery1 =playerFactory(‘皮蛋’,’red’),
plaery2 =playerFactory(‘小乖’,’red’),
plaery3 = playerFactory(‘宝宝’,’red’),
plaery4 =playerFactory(‘小强’,’red’)

//蓝队

var plaery5 =playerFactory(‘黑妞’,’blue’),
plaery6 =playerFactory(‘葱头’,’blue’),
plaery7 =playerFactory(‘胖墩’,’blue’),
plaery8 =playerFactory(‘海盗’,’blue’);

测试让红队全部死忘

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

14.2.2 玩家增多带来的困扰

现在我们已经可以随意地为游戏增加玩家或者队伍,但问题是,每个玩家和其他玩家都是紧耦合在一起的。在此段代码中,每个玩家对象都有两个属性,this.partners和this.enemies,用来保存其他玩家对象的引用。当每个对象的状态发生改变,比如角色移动、吃到道具或者死亡时,都要显式地遍历通知其他对象。

在这个例子中只创建了8个玩家,或许没有对你产生足够的困扰,而如果在一个大型网络游戏中,画面里有成百上千的玩家……

14.2.3 用中介者模式改造泡泡堂游戏

首先还是来定义Player构造函数和player对象的原型方法,在player对象的这些原型方法中,不再负责具体的执行逻辑,而是把操作转交给中介者对象,我们把中介者对象命名为playerDirector

function Player(name,teamColor){
   this.name= name;
   this.teamColor= teamColor;
   this.state='alive';//玩家生存状态
}

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=newPlayer(name,teamColor);
    playerDirector.ReceiveMessage('addPlayer',newPlayer);
    return newPlayer
}

最后我们需要实现这个中介者playerDirector对象,一般有以下两种方式:

o  利用发布—订阅模式。将playerDirector实现为订阅者,各player作为发布者,一旦player的状态发生改变,便推送消息给playerDirector,playerDirector处理消息后反馈发送给其他player

o  在playerDirector中开放一些接收消息的接口,各player可以直接调用接口来给playerDirector发送消息,player只需要传递一个参数给playerDirector,这个参数的目的是使playerDirector可以识别发送者。同样playerDirector接收到消息之后会将处理结果反馈给其他player.

 

我们采用第二种方式:

var playerDirector= (function() {
    var players= {},//保存所有玩家
       
operations = {};//中介者可以执行的操作
    //
新增玩家
   
operations.addPlayer=function(player) {
        var teamColor= player.teamColor;
        player[teamColor] = players[teamColor] || [];
        player[teamColor].push(player);
    }
    //移除玩家
   
operations.removePlayer=function(player) {
        var teamColor= player.teamColor;
        var teamPlayers=players[teamColor] || [];//该队所有成员
       
for (vari=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() {
        var teamColor=players.teamColor;
        var teamPlayers=players[teamColor];
        var all_dead=true;
        for (vari=0,player;player= teamPlayers[i++];) {
            if (player.state!=='dead') {
                all_dead = false;
                break;
            }
        }
        if (all_dead===true) {
            for (vari=0,player;player= teamPlayers[i++];) {
                player.lose();
            }
            for (varcolorinplayers) {
                if (color!=teamColor) {
                    var teamPlayers=players[color];
                    for (vari=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
   
}
})();

可以看到,除了中介者本身,没有一个玩家知道其他任何玩家的存在,玩家与玩家之间的耦合关系已经完全解除,某个玩家的任何操作都不需要通知其它玩家,而只需要给中介者发送一个消息,中介者处理完消息之后会把处理结果反馈给其他的玩家对象。

14.3 中介者模式的例子—购买商品

我看懂了就不往这记啦。略,感谢去看看作者的书吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值