设计模式之组合模式

1. 定义

将对象组合成树状结构以表示“部分-整体”的层次关系,使客户端统一对待单个对象和组合对象,从而简化客户端代码

2. 口语化表述

树木,在生活中很常见

中小学知识告诉我们,树木的水分,从根部吸收,通过树干,到达树叶进行生物活动(如光合作用)

树干有很多分叉,对于任何一个树干来说,需要做的就是:接收上一级树干的水分,然后分给下一级(树干或叶子)

是的,树干的职责非常清晰,就是接收上一级,然后分给下一级,它不必关心全局如何实现的,因为只要每个都这样做,就能实现最终结果

组合模式(对象树模式)的思路大致也是如此,将对象设计为一个树状结构,每个节点对象的职责相同且简单

谈到对象树,那自然会有“树”这种数据结构的优缺点,既简单(代码逻辑上)又复杂(代码设计上)

3. 源码示例

Three.js是著名的前端JavaScript 3D图形库,其基础对象是Object3D,可参考:Object3D – three.js docs (three3d.cn)

Object3D还有自己的Children,依旧是Object3D(三维模型结构大致如此,一个完整的模型通常由很多子模型构成,子模型也可能会有下一级子模型)

所以,这种对象树模式在Three.js的对象中很常见,如果要对这个Object3D做某些操作,往往就会对每个Children调用对应的函数,Children会自然而然地对其Children调用对应的函数(递归调用)

比如下面的getObjectByProperty函数:

getObjectByProperty( name, value ) {

    if ( this[ name ] === value ) return this;

    for ( let i = 0, l = this.children.length; i < l; i ++ ) {

        const child = this.children[ i ];
        const object = child.getObjectByProperty( name, value );

        if ( object !== undefined ) {
            return object;
        }
    }

    return undefined;
}

使用这种对象树模式的好处很显然,逻辑上很简单,只需要对下一级(Children)作用即可(也就是递归、或者“树”结构的优点)

4. 总结

4.1 设计优点

  • 开闭原则

    无需更改现有代码,就可以在原有基础中添加新节点,使其成为对象树的一部分

  • 递归机制

    逻辑上很简单,只需要对上一级和下一级负责

4.2 适用场景

  • 需要实现树状对象结构

  • 以相同方式处理简单和复杂元素

5. 参考资料

[1] 组合设计模式 (refactoringguru.cn)

[2] three.js/src/core/Object3D.js at dev · mrdoob/three.js (github.com)

posted @ 2023-11-29 20:47  当时明月在曾照彩云归  阅读(4)  评论(0编辑  收藏  举报