本文已参与「新人创作礼」活动,一起开启掘金创作之路。
关键词:Command
本质其实就是回调函数。
在没有函数的语言里,命令模式就是函数的替代品(代餐、平替)。
主要作用:拓展业务功能,通过发送命令来解耦执行任务的方法。
最核心的实现手段:把函数当作参数进行传递。
命令模式解决什么问题?
前端开发很多情况下需要通过后端提供的数据,例如后端返回一组按钮的数据。
{ "btns": [ { "code": "submit", "disable": false }, { "code": "valid", "disable": false }, { "code": "cancel", "disable": false } ] }
我们第一反应是:将按钮遍历,然后在点击事件的时候添加相关的业务逻辑:
const btnsTextMap = { submit: '提交', valid: '校验', cancel: '取消' } const onHandle = (code) => { if(code === 'submit') { // ... } // ... } { btns.map(btn => <button onClick={()=>onHandle(item.code)}>{btnsTextMap[btn[item.code]]}</button>) }
后续如果增加新按钮例如:删除。那就需要修改 onHandle 里面的函数,这样其实并不易维护。
来看下类似的功能的demo:
通过命令模式改造后:
通过调用 execute
把要执行的方法当做参数传入,就可以直接执行相关逻辑。
定义
将请求转换为一个包含与请求相关的所有信息的独立对象。能根据不同的请求,将方法参数化、 延迟请求执行或将其放入队列中, 且能实现可撤销操作。
类比日常生活
在餐厅点餐,选好菜品叫服务员下单。厨师收到订单,根据订单配料做菜,然后将做好的菜品放在托盘上,服务员看到托盘后对订单进行检查, 确保所有食物都是你要的, 然后将食物放到了你的桌上。
那份订单就是命令。
拿订餐来说,我需要向厨师发送请求,但是完全不知道厨师的名字和联系方式,也不知道厨师炒菜的方式和步骤。
命令模式把我的订单封装成 command
对象,也就是订餐中的订单对象。厨师只是把拿到的订单执行特定的业务逻辑。
图片来源于 refactoringguru
应用场景
命令模式可以解决哪类问题
主要是用来控制命令的执行,比如:异步、延迟、排队执行命令、撤销重做命令、存储命令、给命令记录日志等。
命令模式的作用不仅是封装运算块,而且可以很方便地给命令对象增加撤销操作。就像订餐时客人可以通过电话来取消订单一样。
具体实现
命令模式的设计思路和具体实现。
命令模式用到最核心的实现手段,就是将函数封装成对象。把函数当作参数进行传递。
interface Command { execute(): void; } class SimpleCommand implements Command { private payload: string; constructor(payload: string) { this.payload = payload; } public execute(): void { console.log( `SimpleCommand: See, I can do simple things like printing (${this.payload})` ); } } class ComplexCommand implements Command { private receiver: Receiver; private a: string; private b: string; constructor(receiver: Receiver, a: string, b: string) { this.receiver = receiver; this.a = a; this.b = b; } public execute(): void { console.log( "ComplexCommand: Complex stuff should be done by a receiver object." ); this.receiver.doSomething(this.a); this.receiver.doSomethingElse(this.b); } } class Receiver { public doSomething(a: string): void { console.log(`Receiver: Working on (${a}.)`); } public doSomethingElse(b: string): void { console.log(`Receiver: Also working on (${b}.)`); } } class Invoker { private onStart: Command; private onFinish: Command; public setOnStart(command: Command): void { this.onStart = command; } public setOnFinish(command: Command): void { this.onFinish = command; } public doSomethingImportant(): void { console.log("Invoker: Does anybody want something done before I begin?"); if (this.isCommand(this.onStart)) { this.onStart.execute(); } console.log("Invoker: ...doing something really important..."); console.log("Invoker: Does anybody want something done after I finish?"); if (this.isCommand(this.onFinish)) { this.onFinish.execute(); } } private isCommand(object): object is Command { return object.execute !== undefined; } } const invoker = new Invoker(); invoker.setOnStart(new SimpleCommand("Say Hi!")); const receiver = new Receiver(); invoker.setOnFinish(new ComplexCommand(receiver, "Send email", "Save report")); invoker.doSomethingImportant();
参考资料: