1. 定义
将一个请求封装成一个对象,从而允许客户端参数化不同的请求、将请求排队或者记录请求日志、以及支持可撤销的操作
2. 口语化表述
假设某餐厅的工作流程如下:
- 顾客在大堂点餐,服务员记录菜单
- 服务员将菜单送到后厨
- 后厨根据菜单做菜
- 服务员根据菜单送到对应的餐桌
在这个场景中,后厨不需要了解顾客做了什么,顾客不需要关心后厨做了什么,只需要按照菜单来做事情
假设顾客在点完餐后又想更改,只需要服务员更改一下对应的菜单即可
这种模式就是命令模式,这里的菜单就是一个请求对象,包含了请求信息
(下面的表述会沿用这个场景)
3. 源码示例
Cesium.js是一个著名的、基于WebGL的GIS前端框架
基于WebGL就不得不提WebGL(OpenGL)的基础概念,比如VAO(顶点数组对象)、VBO(顶点缓冲对象)、Shader Program(着色器)等
每一次渲染,通常都需要执行一系列的WebGL命令(WebGL是个全局状态机,需要使用GL命令控制),如 gl.clearColor
(清屏)、gl.draw
(绘制)等
Cesium.js在渲染模块中,将GL命令封装为Command对象
Cesium中的Command对象包含执行的指令参数和执行方法,比如最简单的ClearCommand:
function ClearCommand(options) {
// ...
this.color = options.color;
this.depth = options.depth;
this.stencil = options.stencil;
this.renderState = options.renderState;
this.framebuffer = options.framebuffer;
this.owner = options.owner;
this.pass = options.pass;
}
ClearCommand.prototype.execute = function (context, passState) {
context.clear(this, passState);
};
ClearCommand包含颜色、深度、通道等指令参数和执行方法context.clear(this, passState)
context.clear()
会执行清除的WebGL指令:
Context.prototype.clear = function (clearCommand, passState) {
// ...
const c = clearCommand.color;
const d = clearCommand.depth;
const s = clearCommand.stencil;
gl.clearColor(c.red, c.green, c.blue, c.alpha);
gl.clearDepth(d);
gl.clearStencil(s);
bindFramebuffer(this, framebuffer);
gl.clear(bitmask);
};
ClearCommand在Scene中的调用流程是:
初始化Scene时初始化ClearCommand
function Scene(options) {
// ...
this._clearColorCommand = new ClearCommand({
color: new Color(),
stencil: 0,
owner: this,
});
// ...
}
执行更新时调用ClearCommand的execute
()方法
Scene.prototype.updateAndExecuteCommands = function (passState, backgroundColor) {
// ...
updateAndClearFramebuffers(this, passState, backgroundColor);
// ...
};
function updateAndClearFramebuffers(scene, passState, clearColor) {
// ...
// Clear the pass state framebuffer.
const clear = scene._clearColorCommand;
Color.clone(clearColor, clear.color);
clear.execute(context, passState);
// ...
}
这么设计的好处是,Command对象可以存储各种参数信息,这些信息也可以随时更改,并且,这个命令在在需要调用时只需要执行自己的execute
方法
具体的Command(如,ClearCommand)只需要根据参数做事情,Scene对象只需要保存这些参数并在需要时执行Command的execute
方法
缺点呢,存储Command对象需要内存开销,开发时封装Command对象需要时间
4. 总结
4.1 设计优点
-
开闭原则
新来的顾客只需要添加菜单即可,新来的厨师只需要处理菜单即可
-
单一职责原则
顾客、厨师只负责做自己的事情
-
实现操作的拦截或者延迟执行
菜单传递到后厨并没有立刻做出菜品,所以顾客可以修改菜单,厨师也可以提前做准备
4.2 适用场景
-
通过操作来参数化对象
将命令封装为一个对象,可以实时改变它的状态
-
将操作放入队列中、操作的执行或者远程执行操作
-
实现操作回滚功能
即撤销上一步命令
5. 参考资料
[1] 命令设计模式 (refactoringguru.cn)
[2] Cesium渲染模块之Command - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)
标签:...,ClearCommand,菜单,模式,命令,Command,passState,设计模式,options From: https://www.cnblogs.com/jiujiubashiyi/p/17897196.html