定义
在应用程序里中,程序由大大小小的单一对象组成,所有这些对象都按照某种关系和规则来通信,但由于这些细粒度对象之间的联系激增,又有可能会反过来降低它们的可复用性。
中介者模式的作用就是解除对象与对象之间的紧耦合关系。增加一个中介者对象后,所有的相关对象都通过中介者对象来通信,而不是互相引用,所以当一个对象发生改变时,只需要通知中介者对象即可。从而使网状的多对多关系变成了相对简单的一对多关系
举个🌰
泡泡糖游戏多人对战,我们可以随意地为游戏增加玩家或者队伍,如果有一个玩家掉线,必须从所有其他玩家的队友列表和敌人列表中都移除这个玩家。游戏还有解除队伍和添加到别的队伍的功能。
上代码
// 玩家对象
class Player {
public name; // 玩家姓名
public teamColor; // 玩家队伍
public state = 'alive'; // 玩家当前状态:alive 生存 die 死亡
constructor(name: string, teamColor: string) { // 初始化玩家需要确定玩家姓名以及玩家队伍
this.name = name;
this.teamColor = teamColor
}
// 该场游戏当前玩家为赢则调用
win() {
console.log('win ' + this.name + this.teamColor)
}
// 该场游戏当前玩家为输则调用
lose() {
console.log('lose ' + this.name + this.teamColor)
}
// 当玩家死亡时调用
die() {
this.state = 'die'
playerDirector.reciveMessage('playerDead', this); // 通知中介者对象做处理
}
// 玩家掉线需移除该玩家
remove() {
playerDirector.reciveMessage('removePlayer', this) // 通知中介者对象做处理
}
// 玩家更换队伍
changeTeam(color: string) {
playerDirector.reciveMessage('changeTeam', this, color) // 通知中介者对象做处理
}
}
// 中介者对象
class PlayerDirector {
public players = {} // 当前所有玩家存储介质
// 添加玩家
addPlayer(player: Player) {
const teamColor = player.teamColor;
this.players[teamColor] = this.players[teamColor] || []
this.players[teamColor].push(player)
}
// 移除玩家
removePlayer(player: Player) {
const teamColor = player.teamColor;
const teamPlayers = this.players[teamColor] || [];
teamPlayers.map((v: Player,i: number) => {
if (v === player) teamPlayers.splice(i, 1)
})
}
// 玩家更换队伍
changeTeam(player: Player, color: string) {
this.removePlayer(player)
player.teamColor = color
this.addPlayer(player)
}
// 玩家死亡,死亡时需判断玩家所在队伍队员是都都为死亡状态,如是,则需要宣布游戏结果
playerDead(player: Player) {
const teamColor = player.teamColor,
teamPlayers = this.players[teamColor]
const notAllDead = teamPlayers.some((p: Player) => {
return p.state !== 'die'
})
if (!notAllDead) { // 全部死亡
teamPlayers.map((p: Player) => {
p.lose();
})
for (const color in this.players) {
if (color !== teamColor) {
this.players[color].map((p: Player) => {
p.win();
})
}
}
}
}
// 对外接受消息接口
reciveMessage(method: string, ...args: any[]) {
this[method](...args)
}
}
// 玩家初始化工厂函数
const playFactory = (name: string, teamColor: string) => {
const newPlayer = new Player(name, teamColor);
playerDirector.reciveMessage('addPlayer', newPlayer); // 初始化时需要往中介者对象同步添加玩家
return newPlayer;
}
// 初始化中介者对象
const playerDirector = new PlayerDirector()
// 初始化红队队伍
const player1 = playFactory('a', 'red')
const player2 = playFactory('b', 'red')
const player3 = playFactory('c', 'red')
const player4 = playFactory('d', 'red')
// 初始化蓝队队伍
const player5 = playFactory('e', 'blue')
const player6 = playFactory('f', 'blue')
const player7 = playFactory('g', 'blue')
const player8 = playFactory('h', 'blue')
// 开始游戏
player1.die()
player2.die()
player6.die()
player3.die()
player4.die()
结果如下:
假设玩家e和玩家f掉线,结果如下:
player5.remove()
player6.remove()
player7.die()
player8.die()
假设玩家a从红队叛变到蓝队,结果如下
player1.changeTeam('blue')
player2.die()
player3.die()
player4.die()
优缺点
从上述例子中我们可以看出,玩家与玩家之间是完全解耦的关系,各个对象只需关注自身功能的实现,对象之间的交互关系交给中介者对象来实现和维护。
不过中介者也存在一些缺点,其中最大的缺点是系统中会新增一个中介者对象,因为对象之间交互的复杂性,转移成了中介者对象的复杂性,从而使得中介者对象变得巨大且难以维护。
所以,我们要衡量对象之间的耦合程度来决定是否采用中介者模式,一般来说,如果对象之间的复杂耦合确实导致调用和维护出现了困难,而且这些耦合度随项目的变化呈指数增长曲线,那我们就可以考虑用中介者模式来重构代码。