设计模式之外观模式

发布时间 2023-12-04 12:28:02作者: 当时明月在曾照彩云归

1. 定义

提供了一个统一的接口,用来访问子系统中的一组接口

2. 口语化表述

工厂里组装台灯,流程、配件等有多种方式,每种台灯有自己的生产线

现在,需要某一种台灯,一种方式是直接去找这个台灯的生产线生成,这会令人烦恼,因为寻找是一件无聊而繁琐的事情

另一种方式是成立一个工厂前台,需要什么台灯就只需要给前台说明,前台会告诉对应的生产线,并将生产好的台灯交付给你

这流程就简单多了,不管是谁来,他都只需和前台联系,然后工厂就会给他对应的产品,这就是外观模式,前台就是工厂的外观

上述情景表述的是产品创建,所以也是简单工厂模式的典型应用(简单工厂模式侧重于创建,而外观模式不局限于创建产品)

下面的描述会沿用这个上述这个场景

3. 源码示例

Cesium.js是一个著名的、基于WebGL的GIS前端框架

基于WebGL就不得不提WebGL(OpenGL)的基础概念,比如VAO(顶点数组对象)、VBO(顶点缓冲对象)等

Cesium.js在渲染模块中,有一个对象叫VertexArrayFacade,该对象大致源码如下:

function VertexArrayFacade(context, attributes, sizeInVertices, instanced) {

  // ...
  const attrs = VertexArrayFacade._verifyAttributes(attributes);
  sizeInVertices = defaultValue(sizeInVertices, 0);

  // Bucket the attributes by usage.
  const length = attrs.length;
  for (let i = 0; i < length; ++i) {
    const attribute = attrs[i];

    usage = attribute.usage;
    attributesForUsage = attributesByUsage[usage];
    if (!defined(attributesForUsage)) {
      attributesForUsage = attributesByUsage[usage] = [];
    }

    attributesForUsage.push(attribute);
  }

  for (usage in attributesByUsage) {
    if (attributesByUsage.hasOwnProperty(usage)) {
      attributesForUsage = attributesByUsage[usage];

      attributesForUsage.sort(compare);
      const vertexSizeInBytes = VertexArrayFacade._vertexSizeInBytes(
        attributesForUsage
      );

      const bufferUsage = attributesForUsage[0].usage;

      const buffer = {
        vertexSizeInBytes: vertexSizeInBytes,
        vertexBuffer: undefined,
        usage: bufferUsage,
        needsCommit: false,
        arrayBuffer: undefined,
        arrayViews: VertexArrayFacade._createArrayViews(
          attributesForUsage,
          vertexSizeInBytes
        ),
      };

      this._allBuffers.push(buffer);
    }
  }
  // ...
  this.resize(sizeInVertices);
}

代码片段看上去有点多,但是不难理解,这个VertexArrayFacade对象主要就是对VertexArray做一系列的处理

外部操作VertexArray时,只需要调用这个VertexArrayFacade对象即可

4. 总结

4.1 设计优点

  • 让代码独立于复杂子系统

    将复杂的过程对外隐藏,外部只需要联系外观对象即可

4.2 适用场景

  • 需要一个指向复杂子系统的直接接口,且该接口的功能有限(对外暴露的函数数量不多)

5. 参考资料

[1] 外观设计模式(门面模式) (refactoringguru.cn)

[2] cesium/packages/engine/Source/Renderer/VertexArrayFacade.js at main · CesiumGS/cesium (github.com)