js常用設(shè)計(jì)模式1-單例模式
js常用設(shè)計(jì)模式2-策略模式
js常用設(shè)計(jì)模式3-代理模式
js常用設(shè)計(jì)模式4-發(fā)布-訂閱模式
js常用設(shè)計(jì)模式5-命令模式
js常用設(shè)計(jì)模式6-組合模式
js常用設(shè)計(jì)模式7-享元模式
js常用設(shè)計(jì)模式8-職責(zé)鏈模式
js常用設(shè)計(jì)模式9-中介者模式
js常用設(shè)計(jì)模式10-裝飾者模式
js常用設(shè)計(jì)模式11-狀態(tài)模式
面向?qū)ο笤O(shè)計(jì)鼓勵(lì)將行為分散到對象中,把對象劃分為更小的粒度,有助于增強(qiáng)對象的可復(fù)用性。但是粒度太小又導(dǎo)致對象之間聯(lián)系增加,進(jìn)一步導(dǎo)致復(fù)用性降低。
中介者模式的作用就是解除對象與對象之間緊密的耦合。
1,現(xiàn)實(shí)中的中介者
機(jī)場指揮者:調(diào)度范圍所的全部飛機(jī)
房產(chǎn)中介:你懂的
2,中介者模式的例子------文字版泡泡堂游戲
定義玩家構(gòu)造函數(shù),有3個(gè)原型方法:win,lose,die:
/**
* 中介者:解除對象和對象之間的耦合,專門用來分發(fā)邏輯事件
*/
//這個(gè)版本只能有兩個(gè)玩家,代碼也十分拉胯
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,為游戲增加隊(duì)伍
之前只有倆玩家,當(dāng)玩家變多的時(shí)候就需要分組了。目前暫時(shí)分成兩組
(1)定義一個(gè)數(shù)組players來保存所有玩家,常見玩家之后,循環(huán)players來給每個(gè)玩家設(shè)置隊(duì)友和敵人:
var players = []
(2)改寫構(gòu)造函數(shù),增加一些屬性:
function Player(name, teamColor) {
this.partners = [] //隊(duì)友列表
this.enemies = [] //敵人列表
this.state = 'live' //玩家狀態(tài)
this.name = name //角色名字
this.teamColor = teamColor //隊(duì)伍顏色
}
(3)玩家勝利之后表現(xiàn)出來:
Player.prototype.win = function () { // 玩家團(tuán)隊(duì)勝利
console.log('winner:' + this.name)
}
Player.prototype.lose = function () { // 玩家團(tuán)隊(duì)失敗
console.log('loser:' + this.name)
}
(4)玩家死亡之后,遍歷其他隊(duì)友的生存狀況,如果全部die,那么隊(duì)伍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) 工廠模式創(chuàng)建玩家:
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,存在的問題
上面的游戲的玩家,有隊(duì)友和敵人的屬性,以至于只能有兩只隊(duì)伍,而且當(dāng)一個(gè)玩家die的時(shí)候,要通知所有的隊(duì)友和敵人并移除,這個(gè)操作很不好,
這個(gè)是很不利于我們的游戲走向國際化的,下面我們來改造上面的代碼
(1)先定義Player構(gòu)造函數(shù)和原型方法,現(xiàn)在player對象不再負(fù)責(zé)具體的邏輯,而是把操作轉(zhuǎn)交給中介者對象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)
}
// 玩家換隊(duì)
Player.prototype.changeTeam = function (color) {
playerDirectory.receiveMessage('changeTeam', this, color)
}
(2) 改寫工廠函數(shù),現(xiàn)在的工廠函數(shù)用處很小了:
//工廠函數(shù),用處很小了已經(jīng)
var playerFactory = function (name, teamColor) {
var newPlayer = new Player(name, teamColor)
playerDirectory.receiveMessage('addPlayer', newPlayer)
return newPlayer
}
(3)最主要也是最重要的,實(shí)現(xiàn)我們的中介者函數(shù)playerDirector,一般有兩種寫法:
- 利用發(fā)布-訂閱模式。將playerDirector作為訂閱者,player作為發(fā)布者,一旦player狀態(tài)改變,就推送消息給playerDirector,playerDirector處理消息后反饋給其他player
- 在playerDirector中開放一些接收消息的接口,各player可以調(diào)用接口給playerDirector發(fā)消息,playerDirector通過參數(shù)來識別發(fā)送者,然后把處理結(jié)果反饋給其他player
這倆差不多,這里使用第二種:
//中介者
var playerDirectory = (function () {
//精髓就在這里
var players = {}, //保存所有玩家
operations = {} //中介者可以執(zhí)行的操作
operations.addPlayer = function (newPlayer) {
var teamColor = newPlayer.teamColor
players[teamColor] = players[teamColor] || [] //如果是新的隊(duì)伍,則創(chuàng)建之
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,中介者模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn)是用中間者之后,對象之間解耦,以中介者和對象的一對多,取代了對象之間的網(wǎng)狀結(jié)構(gòu)。對象的維護(hù)變方便了。
缺點(diǎn)是中介者會(huì)變得比較復(fù)雜,難以維護(hù)。