15.结构型 - 组合模式 (Composite Pattern)

组合模式 (Composite Pattern)

意图: 将对象组合成树形结构以表示"部分-整体"的层次结构; 组合模式使得用户对单个对象和组合对象的使用具有一致性;
主要解决: 它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念, 客户程序可以像处理简单元素一样来处理复杂元素, 从而使得客户程序与复杂元素的内部结构解耦;

UML类图

Pasted image 20231128222702

代码实例

例: 文件管理系统, 节点(Node) 它抽象模糊了简单元素(File)和复杂元素(Folder) 的概念, 把所有节点都当作同一类进行处理

1.抽象节点

public abstract class Node {
    protected String name;//节点命名
    public Node(String name) {//构造节点, 传入节点名; 
        this.name = name;
    }
    //增加后续子节点方法
    protected abstract void add(Node child);
}


2.文件夹实现

public class Folder extends Node {
    //文件夹可以包含子节点(文件夹或者文件); 
    private List<Node> childrenNodes = new ArrayList<>();
    public Folder(String name) {
        super(name);//调用父类"节点"的构造方法命名; 
    }
    @Override
    protected void add(Node child) {
        childrenNodes.add(child);//可以添加子节点; 
    }
}

3.文件实现

public class File extends Node{
    public File(String name) {
        super(name);
    }
    @Override
    protected void add(Node child) {
        System.out.println("不能添加子节点; ");
    }
}

提高了可扩展化

它是怎么模糊了简单元素和复杂元素的概念?

例, 增加一个 打印文件树结构 的需求:

//1. 通用, 打印自己
public abstract class Node {
   ...
   //父方法, 前面输出空格, 打印自己
   public void tree(int space){
      for (int i = 0; i < space; i++) {
         System.out.print(" ");//输出n个空格,
      }
      System.out.println(name);//打印自己的名字
   }
}

//2. 文件, 打印自己
public class File extends Node{
   ...
   //文件的实现, 它没有子节点, 打印自己即可
   public void tree(int space){
      super.tree(space)
   }
}

//3. 文件夹, 打印自己, 还有子节点
public class Folder extends Node{
   ...
   @Override
   public void ls(int space){
      super.ls(space);//调用父类共通的ls方法列出自己的名字; 
      space++;//之后列出的子节点前, 空格数要增加一个了; 
      for (Node node: childrenNodes) {
         node.ls(space);//调用子节点的ls方法; 
      }
   }
}

//4. 最后增加一个从根开始打印实现
public abstract class Node {
   ...
   public void tree(){
      this.tree(0);//多态调用 '文件'和'文件夹'的各自实现
   }
}

组合模式(Composite Pattern)总结

关键角色

  1. 抽象节点(包括叶节点和叶子节点)
  2. 具体节点(叶节点)
  3. 具体节点(叶子节点)

in short 模糊了简单元素和复杂元素的概念, 都抽象出来, 一起处理

组合模式的分类

1.透明组合模式

本例中, Node 声明了add方法其实它应该是只属于文件夹(容器), 文件不是容器无法添加子内容, 这种什么所有抽象的方法的方式, 即是透明组合

透明组合模式中,抽象根节点角色中声明了所有用于管理成员对象的方法;

透明组合模式的缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的,叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供 add()、remove() 等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没有提供相应的错误处理代码)

2.安全组合模式

安全组合模式 UML 类图
Pasted image 20251212185003

  • 在安全组合模式中,在抽象构件角色中没有声明任何用于管理成员对象的方法,而是在树枝节点类中声明并实现这些方法。安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。

组合模式优缺点

组合模式优点

  • 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
  • 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
  • 在组合模式中增加新的树枝节点和叶子节点都很方便,无须对现有类库进行任何修改,符合“开闭原则”。
  • 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子节点和树枝节点的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

组合模式的缺点

  • 使用组合模式的前提在于,你的业务场景必须能够表示成树形结构。所以,组合模式的应用场景也 比较局限,它并不是一种很常用的设计模式。

组合模式适宜场景

  • 处理一个树形结构,比如,公司人员组织架构、订单信息等;
  • 跨越多个层次结构聚合数据,比如,统计文件夹下文件总数;
  • 统一处理一个结构中的多个对象,比如,遍历文件夹下所有 XML 类型文件内容;
posted @ 2025-12-12 18:54  daidaidaiyu  阅读(0)  评论(0)    收藏  举报