设计模式之享元模式
1. 定义
共享多个对象所共有的相同状态,以节省内存和提高性能
2. 口语化举例
现有一台灯工厂,有五个生产线(分别生产五种产品)、两个销售部门
这两销售部门在销售产品出去后,都会直接去找生产线生产,有时两部门同时销售出同一种产品,导致这个产品的生产线繁忙
现在,工厂提出一种新方法:
每个生产线都会生产一部分产品,作为存货,销售部门需要拿货就直接去存货里找,没有再联系生产线
这样做的好处是,销售直接找存货,有存货就共用,没有就再生产,两个销售部门之间共享了产品
共享共同需要的部分,这就是享元模式(享:共享,元:对象)
3. 源码示例
Cesium.js是一个著名的、基于WebGL的GIS前端框架
基于WebGL就不得不提WebGL(OpenGL)的基础概念,比如Shader、Shader Program等
Cesium中有频繁的Shader Program创建操作,而Shader Program由Shader构建,源码中封装了ShaderCache
,用于管理Shader的创建
当需要创建Shader Program时,就会向ShaderCache
中查找是否已有一样的Shader缓存,有就直接共用,没有就创建并缓存
ShaderCache
中获取Shader的代码示例如下:
/**
* Returns a shader program from the cache, or creates and caches a new shader program,
* given the GLSL vertex and fragment shader source and attribute locations.
*
* @param {object} options Object with the following properties:
* @param {string|ShaderSource} options.vertexShaderSource The GLSL source for the vertex shader.
* @param {string|ShaderSource} options.fragmentShaderSource The GLSL source for the fragment shader.
* @param {object} options.attributeLocations Indices for the attribute inputs to the vertex shader.
*
* @returns {ShaderProgram} The cached or newly created shader program.
*/
ShaderCache.prototype.getShaderProgram = function (options) {
// ...
let cachedShader;
if (defined(this._shaders[keyword])) {
cachedShader = this._shaders[keyword];
// No longer want to release this if it was previously released.
delete this._shadersToRelease[keyword];
} else {
const context = this._context;
const vertexShaderText = vertexShaderSource.createCombinedVertexShader(
context
);
const fragmentShaderText = fragmentShaderSource.createCombinedFragmentShader(
context
);
const shaderProgram = new ShaderProgram({
gl: context._gl,
logShaderCompilation: context.logShaderCompilation,
debugShaders: context.debugShaders,
vertexShaderSource: vertexShaderSource,
vertexShaderText: vertexShaderText,
fragmentShaderSource: fragmentShaderSource,
fragmentShaderText: fragmentShaderText,
attributeLocations: attributeLocations,
});
cachedShader = {
cache: this,
shaderProgram: shaderProgram,
keyword: keyword,
derivedKeywords: [],
count: 0,
};
// A shader can't be in more than one cache.
shaderProgram._cachedShader = cachedShader;
this._shaders[keyword] = cachedShader;
++this._numberOfShaders;
}
++cachedShader.count;
return cachedShader.shaderProgram;
};
从示例代码可以知道,ShaderCache
实现了Shader的复用、共用
4. 总结
4.1 设计优点
- 节省大量内存
4.2 适用场景
- 在程序创建大量对象时
5. 参考资料
[1] 享元设计模式 (refactoringguru.cn)
[2] cesium/packages/engine/Source/Renderer/ShaderCache.js at main · CesiumGS/cesium (github.com)