js常用设计模式9-中介者模式
js常用设计模式1-单例模式
js常用设计模式2-策略模式
js常用设计模式3-代理模式
js常用设计模式4-发布-订阅模式
js常用设计模式5-命令模式
js常用设计模式6-组合模式
js常用设计模式7-享元模式
js常用设计模式8-职责链模式
js常用设计模式9-中介者模式
js常用设计模式10-装饰者模式
js常用设计模式11-状态模式
面向对象设计鼓励将行为分散到对象中,把对象划分为更小的粒度,有助于增强对象的可复用性。但是粒度太小又导致对象之间联系增加,进一步导致复用性降低。
中介者模式的作用就是解除对象与对象之间紧密的耦合。
1,现实中的中介者
机场指挥者:调度范围所的全部飞机
房产中介:你懂的
2,中介者模式的例子------文字版泡泡堂游戏
定义玩家构造函数,有3个原型方法:win,lose,die:
/**
* 中介者:解除对象和对象之间的耦合,专门用来分发逻辑事件
*/
//这个版本只能有两个玩家,代码也十分拉胯
function Player(name) {
this.name = name
this.enemy = null //敌人
}
Player.prototype.win = function () {
console.log(this.name + ':win')
}
Player.prototype.lose = function () {
console.log(this.name + ":lose")
}
Player.prototype.die = function () {
this.lose()
this.enemy.win()
}
var player1 = new Player('玩家1')
var player2 = new Player('玩家2')
player1.enemy = player2
player2.enemy = player1
player1.die()
3,为游戏增加队伍
之前只有俩玩家,当玩家变多的时候就需要分组了。目前暂时分成两组
(1)定义一个数组players来保存所有玩家,常见玩家之后,循环players来给每个玩家设置队友和敌人:
var players = []
(2)改写构造函数,增加一些属性:
function Player(name, teamColor) {
this.partners = [] //队友列表
this.enemies = [] //敌人列表
this.state = 'live' //玩家状态
this.name = name //角色名字
this.teamColor = teamColor //队伍颜色
}
(3)玩家胜利之后表现出来:
Player.prototype.win = function () { // 玩家团队胜利
console.log('winner:' + this.name)
}
Player.prototype.lose = function () { // 玩家团队失败
console.log('loser:' + this.name)
}
(4)玩家死亡之后,遍历其他队友的生存状况,如果全部die,那么队伍lose,敌人win:
Player.prototype.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
}
}
if (all_dead == true) {
this.lose()
for (var i = 0, partner; partner = this.partners[i++];) {
partner.lose()
}
for (var i = 0, enemy; enemy = this.enemies[i++];) {
enemy.win()
}
}
}
(5) 工厂模式创建玩家:
var playerFactory = function (name, teamColor) {
var newPlayer = new Player(name, teamColor)
for (var i = 0, player; player = players[i++];) {
if (newPlayer.teamColor === player.teamColor) {
player.partners.push(newPlayer)
newPlayer.partners.push(player)
} else {
player.enemies.push(newPlayer)
newPlayer.enemies.push(player)
}
}
players.push(newPlayer)
return newPlayer
}
(6)游戏耍起来:
var player1 = playerFactory('玩家1', 'red')
var player2 = playerFactory('玩家2', 'red')
var player3 = playerFactory('玩家3', 'red')
var player4 = playerFactory('玩家4', 'blue')
var player5 = playerFactory('玩家5', 'blue')
var player6 = playerFactory('玩家6', 'blue')
player1.die()
player2.die()
player3.die()
4,存在的问题
上面的游戏的玩家,有队友和敌人的属性,以至于只能有两只队伍,而且当一个玩家die的时候,要通知所有的队友和敌人并移除,这个操作很不好,
这个是很不利于我们的游戏走向国际化的,下面我们来改造上面的代码
(1)先定义Player构造函数和原型方法,现在player对象不再负责具体的逻辑,而是把操作转交给中介者对象playerDirector。
function Player(name, teamColor) {
this.name = name
this.teamColor = teamColor
this.state = 'alive'
}
Player.prototype.win = function () {
console.log(this.name + ':win')
}
Player.prototype.die = function () {
this.state = 'dead'
playerDirectory.receiveMessage('playerDead', this)
}
Player.prototype.lose = function () {
console.log(this.name + ':lose')
}
// 移除玩家
Player.prototype.remove = function () {
console.log(this.name + ':remove')
playerDirectory.receiveMessage('removePlayer', this)
}
// 玩家换队
Player.prototype.changeTeam = function (color) {
playerDirectory.receiveMessage('changeTeam', this, color)
}
(2) 改写工厂函数,现在的工厂函数用处很小了:
//工厂函数,用处很小了已经
var playerFactory = function (name, teamColor) {
var newPlayer = new Player(name, teamColor)
playerDirectory.receiveMessage('addPlayer', newPlayer)
return newPlayer
}
(3)最主要也是最重要的,实现我们的中介者函数playerDirector,一般有两种写法:
- 利用发布-订阅模式。将playerDirector作为订阅者,player作为发布者,一旦player状态改变,就推送消息给playerDirector,playerDirector处理消息后反馈给其他player
- 在playerDirector中开放一些接收消息的接口,各player可以调用接口给playerDirector发消息,playerDirector通过参数来识别发送者,然后把处理结果反馈给其他player
这俩差不多,这里使用第二种:
//中介者
var playerDirectory = (function () {
//精髓就在这里
var players = {}, //保存所有玩家
operations = {} //中介者可以执行的操作
operations.addPlayer = function (newPlayer) {
var teamColor = newPlayer.teamColor
players[teamColor] = players[teamColor] || [] //如果是新的队伍,则创建之
players[teamColor].push(newPlayer)
}
operations.removePlayer = function (player) {
var teamPlayers = players[player.teamColor]
for (var i = 0; i < teamPlayers.length; 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) {
for (var i = 0, player; player = teamPlayers[i++];) {
player.lose()
}
for (var color in players) {
if (teamColor !== color) {
var teamPlayers = players[color]
for (var j = 0, player; player = teamPlayers[j++];) {
player.win()
}
}
}
}
}
var receiveMessage = function () {
var message = Array.prototype.shift.call(arguments)
operations[message].apply(this, arguments)
}
return {
receiveMessage: receiveMessage
}
})()
(4)游戏耍起来
var player1 = playerFactory('玩家1', 'red')
var player2 = playerFactory('玩家2', 'red')
var player3 = playerFactory('玩家3', 'red')
var player4 = playerFactory('玩家4', 'blue')
var player5 = playerFactory('玩家5', 'blue')
var player6 = playerFactory('玩家6', 'blue')
player1.die()
player3.remove()
player2.die()
5,中介者模式的优缺点
优点是用中间者之后,对象之间解耦,以中介者和对象的一对多,取代了对象之间的网状结构。对象的维护变方便了。
缺点是中介者会变得比较复杂,难以维护。