命令模式是最簡(jiǎn)單和優(yōu)雅的模式之一,命令模式中的命令(command)指的是一個(gè)執(zhí)行某些特定事情的指令。
設(shè)計(jì)模式的主題總是把不變的事物和變化的事物分離開來,命令模式也不例外。
應(yīng)用場(chǎng)景:請(qǐng)求者需要做一些操作,但是并不需要這些操作是誰來做,只要能被完成就行,請(qǐng)求者和被請(qǐng)求者是松耦合的關(guān)系。
比如點(diǎn)餐時(shí),客人只管點(diǎn)餐,他不需要知道廚師的姓名、聯(lián)系方式,能上菜就行,還要啥自行車。
1,菜單程序
一個(gè)頁面上有10個(gè)按鈕,每個(gè)按鈕都有一個(gè)功能,現(xiàn)在我們來實(shí)現(xiàn)這個(gè)功能:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="button1">刷新</button>
<button id="button2">添加</button>
<button id="button3">刪除</button>
<script>
var button1 = document.getElementById('button1')
var button2 = document.getElementById('button2')
var button3 = document.getElementById('button3')
var bindClick = function (button, func) {
button.onclick = func
}
var MenuBar = {
refresh: function () {
console.log('刷新頁面')
}
}
var SubMenu = {
add: function () {
console.log('增加子菜單')
},
del: function () {
console.log('刪除子菜單')
}
}
//按鈕可以任意添加功能
bindClick(button1, MenuBar.refresh)
bindClick(button2, SubMenu.add)
bindClick(button3, SubMenu.del)
</script>
</body>
</html>
2,用閉包來實(shí)現(xiàn)
現(xiàn)在我們需要添加一些別的東西,不再是小打小鬧了。
setCommand:用來綁定dom對(duì)象和點(diǎn)擊事件
RefreshMenuBarCommand:專門用來包裝點(diǎn)擊事件的,這個(gè)函數(shù)可以擴(kuò)展,以后說不定要實(shí)現(xiàn)撤銷操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="button1">刷新</button>
<button id="button2">添加</button>
<button id="button3">刪除</button>
<script>
//修改成符合策略模式的樣子
var button1 = document.getElementById('button1')
var button2 = document.getElementById('button2')
var button3 = document.getElementById('button3')
var setCommand = function (button, command) {
button.onclick = function () {
command.execute()
}
}
var MenuBar = {
refresh: function () {
console.log('刷新菜單界面')
}
}
var RefreshMenuBarCommand = function (receiver) {
return {
execute: function () {
receiver.refresh()
}
}
}
var refreshMenuBarCommand = RefreshMenuBarCommand(MenuBar)
setCommand(button1, refreshMenuBarCommand)
</script>
</body>
</html>
3,撤銷命令
如果需要撤銷命令怎么辦呢?
我們現(xiàn)在想編寫一個(gè)街頭霸王的小游戲,人物有攻擊、防御、跳躍、蹲下四種操作,每次操作之后都會(huì)保存起來,這樣最后我們可以復(fù)盤。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="replay">播放錄像</button>
<script>
var player = {
attack: function () {
console.log('攻擊')
},
defense: function () {
console.log('防御')
},
jump: function () {
console.log('跳躍')
},
crouch: function () {
console.log('蹲下')
}
}
//創(chuàng)建命令---這個(gè)是命令的執(zhí)行者
var makeComnand = function (receive, state) {
if (receive[state]) {
return receive[state]
}
}
var commands = {
'119': 'jump',
'115': 'crouch',
'97': 'defense',
'100': 'attack'
}
var commandStack = []
document.onkeypress = function (e) {
var keyCode = e.keyCode,
command = makeComnand(player, commands[keyCode])
if (command) {
command()
// 將剛剛執(zhí)行過的命令保存進(jìn)堆棧
commandStack.push(command)
}
}
// 點(diǎn)擊播放錄像
document.getElementById('replay').onclick = function () {
var command
// 從堆棧里依次取出命令并執(zhí)行
while (command = commandStack.shift()) {
command()
}
}
</script>
</body>
</html>
4,小結(jié)
額,這個(gè)我沒啥好說的