前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >精读《设计模式 - Command 命令模式》

精读《设计模式 - Command 命令模式》

作者头像
黄子毅
发布2022-03-14 18:23:51
1.8K0
发布2022-03-14 18:23:51
举报
文章被收录于专栏:前端精读评论

Command(命令模式)

Command(命令模式)属于行为型模式。

意图:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

举例子

如果看不懂上面的意图介绍,没有关系,设计模式需要在日常工作里用起来,结合例子可以加深你的理解,下面我准备了三个例子,让你体会什么场景下会用到这种设计模式。

点菜是命令模式

为什么顾客会找服务员点菜,而不是直接冲到后厨盯着厨师做菜?因为做菜比较慢,肯定会出现排队的现象,而且有些菜可能是一起做效率更高,所以将点菜和做菜分离比较容易控制整体效率。

其实这个社会现象就对应编程领域的命令模式:点菜就是一个个请求,点菜员记录的菜单就是将请求生成的对象,点菜员不需要关心怎么做菜、谁来做,他只要把菜单传到后厨即可,由后厨统一调度。

大型软件系统的操作菜单

大型软件操作系统都有一个特点,即软件非常复杂,菜单按钮非常多。但由于菜单按钮本身并没有业务逻辑,所以通过菜单按钮点击后触发的业务行为不适合由菜单按钮完成,此时可利用命令模式生成一个或一系列指令,由软件系统的实现部分来真正执行。

浏览器请求排队

浏览器的请求不仅会排队,还会取消、重试,因此是个典型的命令模式场景。如果不能将 window.fetch 序列化为一个个指令放入到队列中,是无法实现请求排队、取消、重试的。

意图解释

意图:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

一个请求指的是来自客户端的一个操作,比如菜单按钮点击。重点在点击后并不直接实现,而是将请求封装为一个对象,可以理解为从直接实现:

代码语言:javascript
复制
function onClick() {
  // ... balabala 实现逻辑
}

改为生成一个对象,序列化这个请求:

代码语言:javascript
复制
function onClick() {
  concreteCommand.push({
    // ... 描述这个请求
  })
  // 执行所有命令队列
  concreteCommand.executeAll()
}

看上去繁琐了一些,但得到了后面所说的好处:“从而使你可用不同的请求对客户进行参数化”,也就是可以对任何请求进行参数化存储,我们可以在任意时刻调用。 这相当于掌握了执行时机,可以在任意时刻调用,以实现排队或记录日志,如果再记录下反向操作信息,就可以实现撤销重做了。

结构图

Command 是命令的接口,一般固定有一个 execute 方法。

ConcreteCommand 是命令接口的实现,它会注入具体执行者 Receiver,它实现的 execute 方法会调用 receiver.execute 来具体执行。

Invoker 是执行请求的命令,其实上面都在推入命令,并没有真正执行,如果排队结束或点击撤销重做时,就触发了 Invoker 实际,就该调用对应的 Command 执行啦。

代码例子

下面例子使用 typescript 编写。

首先看最终执行态,最终执行需要先添加命令,再执行命令:

代码语言:javascript
复制
const command1 = new Command('balabala1')
const command2 = new Command('balabala2')

const invoker = new Invoker()
invoker.push(command1)
invoker.push(command2)
invoker.execute()

Invoker 内部用一个队列维护,执行的时候其实是 for 循环执行了每个 command.execute():

代码语言:javascript
复制
class Invoker {
  push(command) {
    // 队列里推入命令
    this.commands.push(command)
  }

  execute() {
    this.commands.forEach(command => command.execute())
    // 别忘了清空 this.commands
  }
}

弊端

命令模式需要注意序列化大小,一般分为:

  1. 仅记录操作。
  2. 记录全量快照。
  3. 全量快照共享内存。

记录操作是较为精细的管理方式,并且可以延伸出协同编辑功能。记录快照要注意尽量共享内存,防止快照过大,而且协同编辑场景因为快照无法做冲突处理,所以快照模式在协同编辑场景无法应用。

另外要识别没必要使用命令模式的场景,对于没有撤销重做的前端大部分场景来说,都无需改为命令模式。

总结

命令模式本质上就是将操作抽象为可序列化的命令,使操作可以在合适的时间执行,这种设计带来了许多额外好处。

利用命令模式可以达到高内聚低耦合的效果,提升代码可维护性,也可以实现撤销重做、协同编辑等功能性需求。

版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端精读评论 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Command(命令模式)
    • 举例子
      • 点菜是命令模式
      • 大型软件系统的操作菜单
      • 浏览器请求排队
    • 意图解释
      • 结构图
        • 代码例子
          • 弊端
            • 总结
            相关产品与服务
            文件存储
            文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档