前言
本系列文章主要根据《JavaScript 设计模式与开发实践》整理而来,其中会加入了一些自己的思考。希望对大家有所帮助。
文章系列
js 设计模式 – 单例模式
js 设计模式 – 策略模式
js 设计模式 – 代理模式
js 设计模式 – 迭代器模式
js 设计模式 – 发布订阅模式
概念
命令模式中的命令 (command) 指的是一个执行某些特定事情的指令。
场景
有时候需要向某些对象发送请求,但是并不知道请求的接收 者是谁,也不知道被请求的操作是什么。如快餐店点餐,我们不需要知道厨师是谁,我们只需要把订单交给服务员
优缺点
请求发送者和请求接收者能够消除彼此之间的耦合关系
例子
按钮点击
简单的实现
<!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″> 点击按钮 1 </button>
<script>
var button1 = document.getElementById(‘button1’)
button1.onclick = function () {
console.log(‘ 刷新菜单目录 ’);
}
</script>
</body>
</html>
如果这个点击事件实现很复杂,需要多人合作完成,那我们不得不深入到 button1.onclick 内部去修改代码,违背了开放封闭原则
命令模式实现
<!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″> 点击按钮 1 </button>
<script>
var button1 = document.getElementById(‘button1’)
var setCommand = function (button, command) {
button.onclick = function () {
command.execute();
}
};
var MenuBar = {
refresh: function () {
console.log(‘ 刷新菜单目录 ’);
}
};
var RefreshMenuBarCommand = function (receiver) {
this.receiver = receiver;
};
RefreshMenuBarCommand.prototype.execute = function () {
this.receiver.refresh();
};
var refreshMenuBarCommand = new RefreshMenuBarCommand(MenuBar);
setCommand(button1, refreshMenuBarCommand);
</script>
</body>
</html>
JavaScript 作为将函数作为一等对象的语言,跟策略模式一样,命令模式也早已融入到了 JavaScript 语言之中。
js 中的命令模式
<!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″> 点击按钮 1 </button>
<script>
var button1 = document.getElementById(‘button1’)
var setCommand = function (button, fn) {
button.onclick = fn
};
var MenuBar = {
refresh: function () {
console.log(‘ 刷新菜单目录 ’);
}
};
setCommand(button1, MenuBar.refresh)
</script>
</body>
</html>
设置背景色的例子
撤销命令
我们现在来实现一个撤销操作的例子:界面上有四个按钮,三个可以设置不同的背景色,undo 按钮可以撤销上一次的操作
<!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>
<div id=”div” style=”height: 100px;width: 100px;background-color: blue”></div>
<button id=”button1″>red</button>
<button id=”button2″>black</button>
<button id=”button3″>yellow</button>
<button id=”undo”>undo</button>
<script>
var button1 = document.getElementById(‘button1’)
var button2 = document.getElementById(‘button2’)
var button3 = document.getElementById(‘button3’)
var undo = document.getElementById(‘undo’)
var div = document.getElementById(‘div’)
var cacheColor = []
var setCommand = function (button, fn) {
button.onclick = fn
};
var commond = {
cache: [],
receiver: null,
execute(newBgColor) {
this.cache.push(this.receiver.style.backgroundColor)
this.receiver.style.backgroundColor = newBgColor
},
undo() {
var oldBgColor = this.cache.pop()
this.receiver.style.backgroundColor = oldBgColor
},
setReceiver(target) {
this.receiver = target
}
}
commond.setReceiver(div)
button1.onclick = function () {
commond.execute(‘red’)
}
button2.onclick = function () {
commond.execute(‘black’)
}
button3.onclick = function () {
commond.execute(‘yellow’)
}
undo.onclick = function () {
commond.undo()
}
</script>
</body>
</html>
重做操作
这里我们增加一个 redo 按钮,以恢复之前的操作,需要一个 currentIndex 来记录当前的索引
<!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>
<div id=”div” style=”height: 100px;width: 100px;background-color: blue”></div>
<button id=”button1″>red</button>
<button id=”button2″>black</button>
<button id=”button3″>yellow</button>
<button id=”undo”>undo</button>
<button id=”redo”>redo</button>
<script>
var button1 = document.getElementById(‘button1’)
var button2 = document.getElementById(‘button2’)
var button3 = document.getElementById(‘button3’)
var undo = document.getElementById(‘undo’)
var div = document.getElementById(‘div’)
var commond = {
cache: [],
currentIndex: 0,
receiver: null,
execute(newBgColor) {
this.receiver.style.backgroundColor = newBgColor
this.currentIndex++
this.cache.push(newBgColor)
console.log(‘execute:’, this.cache, this.currentIndex)
},
undo() {
if (this.currentIndex <= 0) return
var oldBgColor = this.cache[–this.currentIndex]
this.receiver.style.backgroundColor = oldBgColor
console.log(‘undo:’, this.cache, this.currentIndex)
},
redo() {
if (this.currentIndex >= this.cache.length – 1) return
var preBgColor = this.cache[this.currentIndex + 1]
this.currentIndex++
this.receiver.style.backgroundColor = preBgColor
console.log(‘redo:’, this.cache, this.currentIndex)
},
setReceiver(target) {
this.receiver = target
this.cache.push(this.receiver.style.backgroundColor)
console.log(‘setReceiver:’, this.cache, this.currentIndex)
}
}
commond.setReceiver(div)
button1.onclick = function () {
commond.execute(‘red’)
}
button2.onclick = function () {
commond.execute(‘black’)
}
button3.onclick = function () {
commond.execute(‘yellow’)
}
undo.onclick = function () {
commond.undo()
}
redo.onclick = function () {
commond.redo()
}
</script>
</body>
</html>