命令模式将调用者和执行者之间分开,通过命令来映射各种操作,从而达到松耦合的目的。
命令模式的由来,其实是回调(callback)函数的一个面向对象的替代品。JavaScript 作为将函数作为一等对象的语言,跟策略模式一样,命令模式也早已融入到了 JavaScript 语言之中。
应用场景
有时候需要向某些对象发送请求,但是并不知道请求的接收 者是谁,也不知道被请求的操作是什么。此时希望用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系。
命令模式的调用者只需要下达命令,不需要知道命令被执行的具体细节。从而使调用者专注于自己的主流程。
特点
- 松耦合:将请求调用者和请求接收者松耦合
- 生命周期
- 支持撤销
- 支持排队
举例
命令模式实现向左、向右、及撤销操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>命令模式</title>
<style>
#app{width: 100%;max-width: 400px;margin: 0 auto;}
.container{width: 100%;background-color: #ddd;margin-top: 40px;}
.box{width: 25px;height: 15px;background-color: #ff5b5c;}
</style>
</head>
<body>
<div id="app">
<h1>命令模式</h1>
<button id="left">向左</button>
<button id="right">向右</button>
<button id="turnback">撤销</button>
<div style="margin-top: 20px"><strong> history: </strong><span id="history" ></span></div>
<div class="container">
<div id="box" class="box"></div>
</div>
</div>
<script>
const step = 25;
const right = document.getElementById('right');
const left = document.getElementById('left');
const turnback = document.getElementById('turnback');
const historyLog = document.getElementById('history');
class Box{
constructor({pos = 0, id}) {
this.pos = pos;
this.$box = document.getElementById(id);
this.update();
}
moveTo(pos) {
this.pos = pos;
this.update();
}
update() {
this.$box.style.marginLeft = this.pos + 'px';
}
}
class Command {
constructor(box) {
this.pos = box.pos || 0;
this.box = box;
this.history = [this.pos];
historyLog.innerText = this.history;
}
run(dis) {
this.pos = this.pos + dis;
this.box.moveTo(this.pos);
this.history.push(this.pos);
historyLog.innerText = this.history;
console.log('run:', this.pos, this.history);
}
cancel() {
if (this.history.length === 0) {alert('回到起点');return}
const record = this.history.pop();
this.pos = this.history[this.history.length - 1];
this.box.moveTo(this.pos);
historyLog.innerText = this.history;
console.log('cancel:', record, this.history);
}
}
const box = new Box({id: 'box', pos: 2 * step});
const command = new Command(box);
right.addEventListener('click', () => command.run(step));
left.addEventListener('click', () => command.run(-step));
turnback.addEventListener('click', () => command.cancel());
</script>
</body>
</html>