[TOC]
# 中介者模式
解除對(duì)象與對(duì)象之間的緊耦合關(guān)系。增加一個(gè)中介者對(duì)象后,所有的相關(guān)對(duì)象都通過(guò)中介者對(duì)象來(lái)通信,而不是互相引用,所有當(dāng)一個(gè)對(duì)象發(fā)生改變時(shí),只需要通知中介者對(duì)象即可。中介者使各對(duì)象之間耦合松散,而且可以獨(dú)立地改變它們之間的交互。中介者模式使網(wǎng)狀的多對(duì)多關(guān)系變成了相對(duì)簡(jiǎn)單的一對(duì)多關(guān)系。
## 中介者模式的例子---泡泡堂游戲
改造前:
```javascript
// 定義數(shù)組保存所有玩家
var players = [];
// 先定義玩家構(gòu)造函數(shù)
function Player(name, teamColor){
this.partners = []; // 隊(duì)友列表
this.enemies = []; // 敵人列表
this.state = 'live'; // 玩家狀態(tài)
this.name = name; // 角色名字
this.teamColor = null; // 隊(duì)伍顏色
};
// 玩家團(tuán)隊(duì)勝利
Player.prototype.win = function(){
console.log('winner:' + this.name);
};
// 玩家團(tuán)隊(duì)失敗
Player.prototype.lose = function(){
console.log('loser:' + this.name);
};
// 玩家死亡
Player.prototype.die = function(){
var all_dead = true;
this.state = 'dead';
// 遍歷隊(duì)友列表
for(var i=0, partner; partner = this.partners[i++];){
if(partner.state !== 'dead'){
all_dead = false;
break;
}
}
// 如果隊(duì)友全部死亡
if(all_dead === true){
this.lose();
// 通知所有隊(duì)友玩家游戲失敗
for(var i=0, partner; partner = this.partners[i++];){
partner.lose();
}
// 通知所有敵人游戲勝利
for(var i=0, enemy; enmy = this.enemise[i++];){
enemy.win();
}
}
};
// 定義一個(gè)工廠來(lái)創(chuàng)建玩家
var playerFactory = function(name, teamColor){
// 創(chuàng)建新玩家
var newPlayer = new Player(name, teamColor);
// 通知所有玩家有新角色加入
for(var i=0,player; player=players[i++];){
if(player.teamColor === newPlayer.teamColor){ // 同一隊(duì)玩家
player.partners.push(newPlayer); // 互相添加到隊(duì)友列表
newPlayer.partner.push(player);
}else{
player.enemies.push(newPlayer); // 互相添加到敵人列表
newPlayer.enemies.push(player);
}
}
players.push(newPlayer);
return newPlayer;
};
// 創(chuàng)建8個(gè)玩家對(duì)象
var player1 = playerFactory('a', 'red');
var player2 = playerFactory('b', 'red');
var player3 = playerFactory('c', 'red');
var player4 = playerFactory('d', 'red');
var player5 = playerFactory('e', 'blue');
var player6 = playerFactory('f', 'blue');
var player7 = playerFactory('g', 'blue');
var player8 = playerFactory('h', 'blue');
```
這里每個(gè)玩家和其它玩家都是緊緊耦合在一起的。用中介者模式進(jìn)行改造。
```javascript
function Player(name, teamColor){
this.name = name; // 角色名字
this.teamColor = teamColor; // 隊(duì)伍顏色
this.state = 'alive'; // 玩家生存狀態(tài)
}
Player.prototype.win = function(){
console.log('winner:' + this.name);
};
Player.prototype.lose = function(){
console.log('loser:' + this.name);
};
Player.prototype.die = function(){
this.state = 'dead';
playerDirector.ReceiveMessage('playerDead', this); // 給中介者發(fā)送消息,玩家死亡
};
Player.prototype.remove = function(){
playerDirector.ReceiveMessage('removePlayer', this); // 給中介者發(fā)送消息,移除一個(gè)玩家
};
Player.prototype.changeTeam = function(){
playerDirector.ReceiveMessage('changeTeam', this); // 給中介者發(fā)送消息,玩家換隊(duì)
};
var playerFactory = function(name, teamColor){
var newPlayer = new Player(name, teamColor);
playerDirector.ReceiveMessage('addPlayer', newPlayer); // 給中介者發(fā)送消息,新增玩家
return newPlayer;
};
// 實(shí)現(xiàn)playerDirector對(duì)象
var playDirector = (function(){
var players = {}; // 保存所有玩家
var operations = {}; // 中介者可以執(zhí)行的操作
// 新增一個(gè)玩家
operations.add = function(player){
var teamColor = player.teamColor;
players[teamColor] = players[teamColor] || [];
players[teamColor].push(player);
};
// 移除一個(gè)玩家
operations.removePlayer = function(player){
var teamColor = player.teamColor;
var teamPlayers = players[teamColor] || [];
for(var i=teamPlayers.length - 1; i >= 0 ;i --){
if(teamPlayers[i] === player){
teamPlayers.splice(i, 1);
}
}
};
// 玩家換隊(duì)
operations.changeTeam = function(player, newTeamColor){
operations.removePlayer(player); // 從原隊(duì)伍中刪除
player.teamColor = newTeamColor; // 換顏色
operations.addPlayer(player); // 新增玩家到新的隊(duì)伍
}
operations.playerDead = function(player){
var teamColor = player.teamColor;
var teamPlayer = players[teamColor];
var all_dead = true;
// 遍歷隊(duì)友列表
for(var i=0, player; player = teamPlayer[i++];){
if(player.state !== 'dead'){
all_dead = false;
break;
}
}
// 如果隊(duì)友全部死亡
if(all_dead === true){
this.lose();
// 通知所有隊(duì)友玩家游戲失敗
for(var i=0, player; player = teamPlayer[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 {
ReciveMessage: ReceiveMessage
}
})();
// 創(chuàng)建8個(gè)玩家對(duì)象
var player1 = playerFactory('a', 'red');
var player2 = playerFactory('b', 'red');
var player3 = playerFactory('c', 'red');
var player4 = playerFactory('d', 'red');
var player5 = playerFactory('e', 'blue');
var player6 = playerFactory('f', 'blue');
var player7 = playerFactory('g', 'blue');
var player8 = playerFactory('h', 'blue');
```
中介者模式是迎合迪米特法則的一種實(shí)現(xiàn)。迪米特法則也叫最少知識(shí)原則,是指一個(gè)對(duì)象應(yīng)該盡可能少地了解另外的對(duì)象(類(lèi)似不合陌生人說(shuō)話(huà))。如果對(duì)象之間的耦合性太高,一個(gè)對(duì)象發(fā)生改變之后,難免會(huì)影響到其他的對(duì)象。而在中介者模式里,對(duì)象之間幾乎不知道彼此的存在,它們只能通過(guò)中介者對(duì)象來(lái)互相影響對(duì)方。
中介者模式最大的缺點(diǎn)是系統(tǒng)中會(huì)新增一個(gè)中介者對(duì)象,因?yàn)閷?duì)象之間交互的復(fù)雜性,轉(zhuǎn)移成了中介者對(duì)象的復(fù)雜性,使得中介者對(duì)象經(jīng)常是巨大的。中介者對(duì)象自身往往就是一個(gè)難以維護(hù)的對(duì)象。
寫(xiě)程序是為了快速完成項(xiàng)目交付生產(chǎn),而不是堆砌模式和過(guò)渡設(shè)計(jì)。關(guān)鍵就在于如何去衡量對(duì)象之間的耦合程度。如果對(duì)象之間的復(fù)雜耦合確實(shí)導(dǎo)致調(diào)用和維護(hù)出現(xiàn)了困難,而且這些耦合度隨項(xiàng)目的變化呈指數(shù)增長(zhǎng)曲線(xiàn),那就可以考慮用中介者模式來(lái)重構(gòu)代碼。
