一, 定义
在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式
二, 场景和实现
比如现在有个前端页面, 里边有10个Button, 各个按钮分别负责不同的点击行为, 两个前端开发分工合作, 一个负责绘制Button, 一份负责实现点击后的行为.
这个场景中不变的是: 点击按钮, 变化的是点击之后的行为不同.
// 不变的是点击按钮会执行一个命令
const bindClick = (btn, onClick) => {
btn.onClick = onClick;
};
// 变化的是命令的行为不一样
const MenuBar = {
refresh: () => {
console.log('刷新页面');
},
};
const SubMenu = {
add: () => {
console.log('添加子菜单');
},
del: () => {
console.log('删除子菜单');
},
};
// 给执行者绑定命令
bindClick(btn1, MenuBar.refresh);
bindClick(btn2, SubMenu.add);
bindClick(btn3, SubMenu.del);
函数是js中的一等公民, 一般情况不需要创建命令对象, 函数可以直接作为命令对象使用.
但是在比较复杂的例子中, 命令对象中需要接收者.
// 命令的执行者
const Receiver = {
attack: () => {
console.log('攻击');
},
defense: function () {
console.log('防御');
},
jump: function () {
console.log('跳跃');
},
crouch: function () {
console.log('蹲下');
},
};
// 创建命令对象
const makeCommand = (receiver, state) => {
return () => {
receiver[state]();
};
};
// 请求命令
const attackReq = makeCommand(Receiver, 'attack');
attackReq();
const defenseReq = makeCommand(Receiver, 'defense');
defenseReq();
const jumpReq = makeCommand(Receiver, 'jump');
jumpReq();
三, 总结
实现命令请求者和命令接收者之间的解耦, 主要是怎么封装命令对象, 简单的使用函数, 复杂点的将接收者封装进命令对象, 再复杂的需要撤 销,取消,回放等操作, 需要用列表存储命令.