命令模式是最简单和优雅的模式之一,命令模式中的命令(command)指的是一个执行某些特定事情的指令。
设计模式的主题总是把不变的事物和变化的事物分离开来,命令模式也不例外。
应用场景:请求者需要做一些操作,但是并不需要这些操作是谁来做,只要能被完成就行,请求者和被请求者是松耦合的关系。
比如点餐时,客人只管点餐,他不需要知道厨师的姓名、联系方式,能上菜就行,还要啥自行车。
1,菜单程序
一个页面上有10个按钮,每个按钮都有一个功能,现在我们来实现这个功能:
<!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,用闭包来实现
现在我们需要添加一些别的东西,不再是小打小闹了。
setCommand:用来绑定dom对象和点击事件
RefreshMenuBarCommand:专门用来包装点击事件的,这个函数可以扩展,以后说不定要实现撤销操作
<!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,撤销命令
如果需要撤销命令怎么办呢?
我们现在想编写一个街头霸王的小游戏,人物有攻击、防御、跳跃、蹲下四种操作,每次操作之后都会保存起来,这样最后我们可以复盘。
<!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('蹲下')
}
}
//创建命令---这个是命令的执行者
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()
// 将刚刚执行过的命令保存进堆栈
commandStack.push(command)
}
}
// 点击播放录像
document.getElementById('replay').onclick = function () {
var command
// 从堆栈里依次取出命令并执行
while (command = commandStack.shift()) {
command()
}
}
</script>
</body>
</html>
4,小结
额,这个我没啥好说的