A structure of simple and composite objects which makes the total object more than just the sum of its parts.

    将对象组合成「树形结构」以表示「部分」和「整体」的层次结构。Composite 使得用户对单个对象和组合对象的使用具有「一致性」。


    动机:创建较为复杂的数据对象层次结构,比如 DOM Tree。


    适用性:

    • 表示对象的「部分 - 整体」的层次结构。
    • 希望用户忽略组合对象和单个对象的不同,用户统一地使用组合结构中所有的对象。

    代码结构:

    典型的 MVC 中,View 层就是经典的「Composite」的案例。


    1. declare interface IDrawable {
    2. draw();
    3. }
    4. class Graphic implements IDrawable {
    5. public draw() {};
    6. }
    7. class Line extends Graphic {
    8. public draw() {};
    9. }
    10. class Text extends Graphic {
    11. public draw() {};
    12. }
    13. class Picture extends Graphic {
    14. public draw() {};
    15. }
    16. class CompositeGraphic implements IDrawable {
    17. private _children: Graphic[];
    18. // 使之行为和 Graphc 保持一致
    19. public draw() {
    20. this._children.forEach(c => c.draw());
    21. }
    22. }
    23. class GraphicBook {
    24. public recursivelyParse(elements) {
    25. return new CompositeGraphic(elements);
    26. }
    27. public parse(ele) {
    28. if (Graphic.isLine(ele)) return new Line(ele);
    29. return typeof ele === 'string' ? new Text(ele) : new Picture(ele);
    30. }
    31. public generatePresentationLayer(str) {
    32. const treeData = JSON.parse(str);
    33. return treeData.map(t => t.children ? recursivelyParse(t.children) : parse(t));
    34. }
    35. }

    实现思路:

    • 考虑「显式地」父组件引用。
    • 考虑「共享」组件和 Flyweight 模式的使用。
    • 最大化 Composite 接口,让用户不知道是 Leaf or Composite 类型,使它们看起来是行为一致的
    • 声明 Composite 管理子部件的操作,包括使用 Cache / Buffer 提高操作效率,或者管理增删查改。

    协作:操作如果是一个叶子节点,则直接执行,否则由组合节点通过循环的形式执行。


    效果:

    • 定义了包含基本对象和组合对象的类层次结构。
    • 简化客户端代码。用户不用担心组合对象和独立对象的操作 API 不一致性。
    • 更容易增加新的类型组件。
    • 使设计更加一般化。

    关联:

    Composite 模式经常伴随:Chain of Responsiblity (请求冒泡处理)、Decorator (动态修饰对象的方法)等设计模式一起使用。

    当然 Flyweight 用以共享对象元,以及 Iterator 用来遍历 Composite 对象也是合理的。

    使用 Visitor 模式来将本应该分布在 CompositeLeaf 类中的操作和行为局部化。