中介者模式
例子:
- 机场指挥塔
- 博彩公司
- 泡泡堂,对人对战,好友加入,敌人加入,好友死亡,全部阵亡等消息通知。
- 商品选择页对属性节点和显示节点的管理。
概念
解除对象与对象之间的紧耦合关系。增加一个中介者对象后,所有的相关对象都通过中介者对象来通信,而不是互相引用,
所以当一个对象发生改变时,只需要通知中介者对象即可。
中介者使各对象之间耦合松散,而且可以独立地改变它们之间的交互。
使网状的多对多关系变成了相对简单的一对多关系
中介者模式是迎合迪米特法则的一种实现。迪米特法则也叫最少知识原则,是指一个对象应该尽可能少地了解另外的对象(类似不和陌生人说话)。如果对象之间的耦合性太高,一个对象发生改变之后,难免会影响到其他的对象
中介者模式和策略模式的对比,但它解决的是对象的多对多通信的问题,
而策略模式解决的是一个支路的各个分支的情况对应的算法策略。
作用
中介者模式使各个对象之间得以解耦,以中介者和对象之间的一对多关系取代了对象之间的网状多对多关系。
各个对象只需关注自身功能的实现,对象之间的交互关系交给了中介者对象来实现和维护。
缺点
系统中会新增一个中介者对象,因为对象之间交互的复杂性,
转移成了中介者对象的复杂性,使得中介者对象经常是巨大的。
中介者对象自身往往就是一个难以维护的对象。
中介者对象要占去一部分内存
适用场景
如果对象之间的复杂耦合确实导致调用和维护出现了困难,
而且这些耦合度随项目的变化呈指数
增长曲线,那我们就可以考虑用中介者模式来重构代码
// 泡泡堂游戏
// 两个人
/* 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 + 'lose')
}
Player.prototype.die = function () {
this.lose()
this.enemy.win()
}
let player1 = new Player('dd')
let player2 = new Player('cc')
player1.enemy = player2
player2.enemy = player1
player1.die() */
// 多人
/* let players = []
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.prototype.die = function() {
// 当有人死了,标记当前人的状态为死亡。
let all_dead = true
this.state = 'dead'
// 查看是否全部阵亡
for (let i = 0; i < this.partners.length; i++) {
const partner = this.partners[i];
if (partner.state !== 'dead') {
all_dead = false
break
}
}
// 全部阵亡通知双方
if (all_dead === true) {
// 通知自己全部失败
this.lose()
for (let i = 0; i < this.partners.length; i++) {
const partner = this.partners[i];
// 通知伙伴输了
partner.lose()
}
for (let i = 0; i < this.enemies.length; i++) {
// 通知敌人赢了
const enemy = this.enemies[i];
enemy.win()
}
}
}
// 玩家工厂
let PlayerFactory = function(name, teamColor) {
// 新玩家
let newPlayer = new Player(name, teamColor)
// 查找队友和敌人,绑定彼此关系。
for (let i = 0; i < players.length; i++) {
const player = players[i];
if (player.teamColor === newPlayer.teamColor) { // 互相加好友
player.partners.push(newPlayer)
newPlayer.partners.push(player)
} else { // 互相加敌人
player.enemies.push(newPlayer)
newPlayer.enemies.push(player)
}
}
// 新成员加入
players.push(newPlayer)
return newPlayer
}
let player1 = PlayerFactory('dd', 'red')
let player2 = PlayerFactory('cc', 'red')
let player3 = PlayerFactory('jj', 'red')
let player4 = PlayerFactory('niky', 'red')
let player5 = PlayerFactory('coco', 'blue')
let player6 = PlayerFactory('bar', 'blue')
let player7 = PlayerFactory('joney', 'blue')
let player8 = PlayerFactory('foo', 'blue')
player1.die()
player2.die()
player3.die()
player4.die()
*/
// 中介者模式
let playerDirector = (function() {
let players = {}
let operations = {}
operations.addPlayer = function(player) {
let teamColor = player.teamColor
players[teamColor] = players[teamColor] || []
players[teamColor].push(player)
}
operations.removePlayer = function(player) {
let teamColor = player.teamColor
let teamPlayers = players[teamColor] || []
for (let 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.playerDie = function(player) {
let teamColor = player.teamColor
teamPlayers = players[teamColor]
let all_die = true
for (let i = 0; i < teamPlayers.length; i++) {
if (teamPlayers[i].state !== 'dead') {
all_die = false
break
}
}
if (all_die) {
for (let i = 0; i < teamPlayers.length; i++) {
teamPlayers[i].lose()
}
for (const color in players) {
if (Object.hasOwnProperty.call(players, color)) {
if (color !== teamColor) {
const enemies = players[color];
for (let i = 0; i < enemies.length; i++) {
enemies[i].win();
}
}
}
}
}
}
let reciveMessage = function() {
let message = Array.prototype.shift.call(arguments)
operations[message].apply(this, arguments)
}
return {
reciveMessage
}
})()
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('playerDie', this)
}
Player.prototype.remove = function() {
playerDirector.reciveMessage('removePlayer', this)
}
Player.prototype.changeTeam = function(color) {
playerDirector.reciveMessage('changeTeam', this, color)
}
let PlayerFactory = function(name, teamColor) {
let newPlayer = new Player(name, teamColor)
playerDirector.reciveMessage('addPlayer', newPlayer)
return newPlayer
}
let player1 = PlayerFactory('dd', 'red')
let player2 = PlayerFactory('cc', 'red')
let player3 = PlayerFactory('jj', 'red')
let player4 = PlayerFactory('niky', 'red')
let player5 = PlayerFactory('coco', 'blue')
let player6 = PlayerFactory('bar', 'blue')
let player7 = PlayerFactory('joney', 'blue')
let player8 = PlayerFactory('foo', 'blue')
player1.die()
player2.die()
player3.die()
player4.die()
另一个例子:
// 购买手机
// 规格有:颜色、数量,后面可以不断加入其他规格
let goods = {
'red|32G': 1,
'red|16G': 7,
'blue|32G': 6,
'blue|16G': 3
}
let color = 'red'
let number = 2
let memory = '32G'
let curNumber = {text: ''}
let curColor = {text: ''}
let curMemory = {text: ''}
const mediator = function(obj) {
let stock = goods[`${color}|${memory}`] // 内存数量
if(obj === 'color') {
curColor.text = color
} else if (obj === 'memory') {
curMemory.text = memory
} else if (obj === 'number') {
curNumber.text = number
}
if(!color) {
console.log('请选择颜色')
return
}
if(((number - 0) | 0 ) !== number - 0 ) {
console.log('请输入正整数')
return
}
if(number > stock) {
console.log('库存不足')
return
}
if(!memory) {
console.log('请选择内存大小')
return
}
console.log('放入购物车')
}
const colorChange = () => {
mediator('color')
}
const numberChange = () => {
mediator('number')
}
// 加一个内存属性
const memoryChange = () => {
mediator('memory')
}
// colorChange()
// numberChange()
// memoryChange()
实现思路
他们的写法都是一个函数提供查找下标对应的方法去执行。
具体实现: 在对象中使用闭包保存数据,定义函数方法,然后定义一个接受函数,对接受的命令查找对应的方法进行处理。
外部对象行为彼此分开,想执行的行为通过消息传递给中介,中介获取消息后执行对应的函数来处理中央数据。