命令模式,指的是执行特定操作的指令
命令模式将请求与实现解耦并封装成独立对象,从而使不同的请求对客户端的实现参数化。
命令模式最常见的应用场景是:向对象发送请求,但是不知道想请求的接收者是谁,也不知道接收的请求是什么,因此需要通过一种松耦合的方式来设计程序。
拿订餐来说,客人需要向厨师发送请求,但是完全不知道这些厨师的名字和联系方式,也不知道厨师炒菜的方式和步骤。命令模式把客人订餐的请求封装成command对象,也就是订餐中的订单对象。这个对象可以在程序中被四处传递,就像订单可以从服务员手中传到厨师的手中。这样一来,客人不需要知道厨师的名字,从而解开了请求调用者和请求接收者之间的耦合关系
相对于过程化的请求调用,command对象拥有更长的生命周期。对象的生命周期是跟初始请求无关的,因为这个请求已经被封装在了command对象的方法中,成为了这个对象的行为。我们可以在程序运行的任意时刻去调用这个方法,就像厨师可以在客人预定1个小时之后才帮他炒菜,相当于程序在1个小时之后才开始执行command对象的方法。
命令模式的实现:将具体的业务逻辑封装成对象,对象暴露一个参数化的接口,通过调用这个接口并传递参数实现调用命令对象中的一些方法。
命令模式包含一个command对象和execute函数,execute函数用来执行具体的命令方法,command对象用来存储各种命令。
let command = (function (){
let Command = {
display(){}
};
return function execute(commandName, ...args){
Command[commandName].call(this, ...args);
}
})();
为了更加方便也可以让命令模式一次执行多条命令
function execute(commands){
if(commands.length){
for(let i = 0; i < commands.length; i++){
let command = commands[i];
Command[command.commandName].call(Command, ...command.params);
}
}
}
这种一组命令的集合叫做宏命令,通过执行宏命令的方式,一次可以执行一批命令。
我们在使用canvas绘图的时候经常会调用内置方法,这个时候就会经常使用canvas上下文,这在多人开发项目中是耦合度较高的,如果某个人修改了canvas上下文,那么后果是无法估计的,常用的做法是将canvas上下文的引用封装在命令对象内部,如果某人想绘图,直接通过命令对象调用一条命令即可。
let canvasCommand = (function (){
const canvas = document.getElementbyId('canvasId');
const ctx = canvas.getContext('2d');
const Command = {
fillStyle(style){
ctx.fillStyle = style;
},
fillRect(x,y,width,height){
ctx.fillRect(x,y,width,height);
}
};
return function execute(commands){
if(commands.length){
for(let i = 0; i < commands.length; i++){
let command = commands[i];
Command[command.commandName].call(Command, ...command.params);
}
}
}
)();
canvasCommand([{commandName:'fillRect', params:[0,0,100,100]}])
上面的代码将canvas上下文封装在命令对象内部,不被外部访问,保护canvas上下文不会被修改,同时暴露对应的绘图接口给外部,可以通过命令的形式绘图。