前端设计模式(5)--命令模式

103 阅读2分钟

一, 定义

在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式

二, 场景和实现

比如现在有个前端页面, 里边有10Button, 各个按钮分别负责不同的点击行为, 两个前端开发分工合作, 一个负责绘制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();

三, 总结

实现命令请求者和命令接收者之间的解耦, 主要是怎么封装命令对象, 简单的使用函数, 复杂点的将接收者封装进命令对象, 再复杂的需要撤 销,取消,回放等操作, 需要用列表存储命令.