资讯专栏INFORMATION COLUMN

JavaScript设计模式(七):命令模式

lixiang / 432人阅读

摘要:支持撤销,队列,宏命令等功能。宏命令宏命令一组命令集合命令模式与组合模式的产物发布者发布一个请求,命令对象会遍历命令集合下的一系列子命令并执行,完成多任务。

命令模式:请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

生活小栗子:客户下单,订单记录了客户购买的产品,仓库根据订单给客户备货。

模式特点

命令模式由三种角色构成:

发布者 invoker(发出命令,调用命令对象,不知道如何执行与谁执行);

接收者 receiver (提供对应接口处理请求,不知道谁发起请求);

命令对象 command(接收命令,调用接收者对应接口处理发布者的请求)。

发布者 invoker 和接收者 receiver 各自独立,将请求封装成命令对象 command ,请求的具体执行由命令对象 command 调用接收者 receiver 对应接口执行。

命令对象 command 充当发布者 invoker 与接收者 receiver 之间的连接桥梁(中间对象介入)。实现发布者与接收之间的解耦,对比过程化请求调用,命令对象 command 拥有更长的生命周期,接收者 receiver 属性方法被封装在命令对象 command 属性中,使得程序执行时可任意时刻调用接收者对象 receiver 。因此 command 可对请求进行进一步管控处理,如实现延时、预定、排队、撤销等功能。

代码实现
class Receiver {  // 接收者类
  execute() {
    console.log("接收者执行请求");
  }
}

class Command {   // 命令对象类
  constructor(receiver) {
    this.receiver = receiver;
  }
  execute () {    // 调用接收者对应接口执行
    console.log("命令对象->接收者->对应接口执行");
    this.receiver.execute();
  }
}

class Invoker {   // 发布者类
  constructor(command) {
    this.command = command;
  }
  invoke() {      // 发布请求,调用命令对象
    console.log("发布者发布请求");
    this.command.execute();
  }
}

const warehouse = new Receiver();       // 仓库
const order = new Command(warehouse);   // 订单
const client = new Invoker(order);      // 客户
client.invoke();

/*
输出:
  发布者发布请求
  命令对象->接收者->对应接口执行
  接收者执行请求
*/
应用场景
有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。需要一种松耦合的方式来设计程序,使得发送者和接收者能够消除彼此之间的耦合关系。
——《JavaScript 设计模式与开发实践》

不关注执行者,不关注执行过程;

只要结果,支持撤销请求、延后处理、日志记录等。

优缺点

优点:

发布者与接收者实现解耦;

可扩展命令,对请求可进行排队或日志记录。(支持撤销,队列,宏命令等功能)。

缺点:

额外增加命令对象,非直接调用,存在一定开销。

宏命令
宏命令:一组命令集合(命令模式与组合模式的产物)

发布者发布一个请求,命令对象会遍历命令集合下的一系列子命令并执行,完成多任务。

// 宏命令对象
class MacroCommand {
  constructor() {
    this.commandList = [];  // 缓存子命令对象
  }
  add(command) {            // 向缓存中添加子命令
    this.commandList.push(command);
  }
  exceute() {               // 对外命令执行接口
    // 遍历自命令对象并执行其 execute 方法
    for (const command of this.commandList) {
      command.execute();
    }
  }
}

const openWechat = {  // 命令对象
  execute: () => {
    console.log("打开微信");
  }
};

const openChrome = {  // 命令对象
  execute: () => {
    console.log("打开Chrome");
  }
};

const openEmail = {   // 命令对象
  execute: () => {
    console.log("打开Email");
  }
}

const macroCommand = new MacroCommand();

macroCommand.add(openWechat); // 宏命令中添加子命令
macroCommand.add(openChrome); // 宏命令中添加子命令
macroCommand.add(openEmail);  // 宏命令中添加子命令

macroCommand.execute();       // 执行宏命令
/* 输出:
打开微信
打开Chrome
打开Email
*/
傻瓜命令与智能命令
傻瓜命令:命令对象需要接收者来执行客户的请求。

智能命令:命令对象直接实现请求,不需要接收者,“聪明”的命令对象。

“傻瓜命令” 与 “智能命令” 的区别在于是否有 “接收者” 对象。

// openWechat 是智能命令对象,并没有传入 receiver 接收对象
const openWechat = {
  execute: () => {  // 命令对象直接处理请求
    console.log("打开微信");
  }
};

没有 “接收者” 的智能命令与策略模式很类似。代码实现类似,区别在于实现目标不同。

策略模式中实现的目标是一致的,只是实现算法不同(如目标:根据KPI计算奖金);

智能命令的解决问题更广,目标更具散发性。(如目标:计算奖金/计算出勤率等)。

参考文章

《JavaScript 设计模式与开发实践》

本文首发Github,期待Star!
https://github.com/ZengLingYong/blog

作者:以乐之名
本文原创,有不当的地方欢迎指出。转载请指明出处。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105635.html

相关文章

  • JavaScript设计模式:装饰者模式

    摘要:装饰者模式装饰者模式提供比继承更有弹性的替代方案。装饰者用于包装同接口的对象,用于通过重载方法的形式添加新功能,该模式可以在被装饰者的前面或后面加上自己的行为以达到特定的目的。简单的理解给对象动态添加职责的方式称为装饰着模式。 装饰者模式 装饰者模式提供比继承更有弹性的替代方案。装饰者用于包装同接口的对象,用于通过重载方法的形式添加新功能,该模式可以在被装饰者的前面或后面加上自己的行为...

    alexnevsky 评论0 收藏0
  • JavaScript 设计模式读书笔记()——适配器模式

    摘要:与门面模式的联系本文要说的适配器模式和上一篇门面模式在思想上有相似之处,所以放在一起说。我们以中的一个为例,说说实际应用中的适配器模式的使用方法。而如果实现层的问题不大,要解决一部分适配问题的话,适配器模式就是很好的选择了。 与门面模式的联系 本文要说的适配器模式和上一篇门面模式在思想上有相似之处,所以放在一起说。它们都对类的接口进行了一些改变。门面模式是把相似的或是完成相关任务的接...

    AZmake 评论0 收藏0
  • 编程模型(范式)小结

    摘要:参考链接面向对象编程模型现在的很多编程语言基本都具有面向对象的思想,比如等等,而面向对象的主要思想对象,类,继承,封装,多态比较容易理解,这里就不多多描述了。 前言 在我们的日常日发和学习生活中会常常遇到一些名词,比如 命令式编程模型,声明式编程模型,xxx语言是面向对象的等等,这个编程模型到处可见,但是始终搞不清是什么?什么语言又是什么编程模型,当你新接触一门语言的时候,有些问题是需...

    miya 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<