众多网页游戏的“宠儿”:JavaScript中的中介者模式

众所周知,在程序中,程序是由大大小小的单一对象组成的。所有这些对象都按照某种关系和规则来通信 —— 引用。
这导致了一些问题:当程序越来越大,对象越来越多,他们之间的关系也越来越复杂。有时甚至就会形成交叉的网状结构。这样一来,当我们改变或删除其中一个对象时,有可能需要通知所有引用到它的对象…

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


笔者感觉【中介者模式】和【发布-订阅模式】、vue中的【Bus总线机制】都有异曲同工之妙。它比发布-订阅多了一个“中介”,又比Bus多了一个“对象集合”;
中介者模式的存在,很大程度上解除了对象之间的紧耦合关系,而且不必再为“增加队友”时的性能和效率问题而发愁。

…它们仅仅通知中介者它们改变了,同时把自身作为参数传进去,以便中介者辨别是谁发生了改变。剩下的事情都交给中介者对象来完成。这样一来,无论修改还是新增,都只需改动中介者对象里的代码。


你是否知道曾经风靡一时的游戏:泡泡堂?多人对战、组队、叛变…
我们用【中介者模式】来模拟一下主要功能:

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.reciveMessage( 'playerDead', this ); // 给中介者发送消息,玩家死亡
}; 
//移除玩家
Player.prototype.remove = function(){ 
	playerDirector.reciveMessage( 'removePlayer', this ); // 给中介者发送消息,移除一个玩家
};
//玩家换队
Player.prototype.changeTeam = function( color ){ 
	playerDirector.reciveMessage( 'changeTeam', this, color ); // 给中介者发送消息,玩家换队
};

//工厂函数
var playerFactory = function( name, teamColor ){ 
	var newPlayer = new Player( name, teamColor ); // 创造一个新的玩家对象
	playerDirector.reciveMessage( 'addPlayer', newPlayer ); // 给中介者发送消息,新增玩家
	return newPlayer; 
};

对于中介者(playerDirector),这里我们采用“接口”的方式 —— ,playerDirector开放一个对外暴露的接口 reciveMessage,负责接收 player 对象发送的消息,并处理:

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(); // 本队所有玩家 lose 
			} 
			for ( var color in players ){ 
				if ( color !== teamColor ){ 
					var teamPlayers = players[ color ]; // “其他队伍”的玩家
					for ( var i = 0, player; player = teamPlayers[ i++ ]; ){ 
						player.win(); // “其他队伍”所有玩家 win 
					} 
				} 
			} 
		} 
	}; 
 
	var reciveMessage = function(){ 
		var message = Array.prototype.shift.call( arguments );
		operations[ message ].apply( this, arguments ); 
	}; 
	return { 
		reciveMessage   //reciveMessage:reciveMessage 暴露接口
	} 
})();

可以看到,除了中介者本身,没有一个玩家知道其他任何玩家的存在,玩家与玩家之间的耦合关系已经完全解除,某个玩家的任何操作都不需要通知其他玩家,而只需要给中介者发送一个消息,中介者处理完消息之后会把处理结果反馈给其他的玩家对象。我们还可以继续给中介者扩展更多功能,以适应游戏需求的不断变化。

发布了195 篇原创文章 · 获赞 391 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_43624878/article/details/103871506