设计模式之组合模式
定义
将对象组合成树形结构以表示"部分-整体"的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。如电脑中文件和文件夹的结构。
结构

- Component,抽象构件,为叶子节点对象和组合对象声明公共接口,并实现它们的默认行为。
- Leaf,叶子节点对象,不包含其他的子节点对象。
- Composite,组合对象,包含子节点,实现了抽象构件中定义的行为。
简单实现
抽象构件
public abstract class Component {
  protected String name;
  protected Component(String name) {
    this.name = name;
  }
  public void addChild(Component child) {
    throw new UnsupportedOperationException();
  }
  public void removeChild(Component child) {
    throw new UnsupportedOperationException();
  }
  public Component getChild(int index) {
    throw new UnsupportedOperationException();
  }
  public abstract void operation();
}
叶子节点对象
public class Leaf extends Component {
  public Leaf(String name) {
    super(name);
  }
  @Override
  public void operation() {
    System.out.println(name + " operation");
  }
}
组合对象
import java.util.ArrayList;
import java.util.List;
public class Composite extends Component {
  private final List<Component> children = new ArrayList<>();
  public Composite(String name) {
    super(name);
  }
  public void addChild(Component child) {
    children.add(child);
  }
  public void removeChild(Component child) {
    children.remove(child);
  }
  public Component getChild(int index) {
    if (index < 0 || index >= children.size()) {
      return null;
    }
    return children.get(index);
  }
  @Override
  public void operation() {
    System.out.println(name + " operation");
    for (Component child : children) {
      child.operation();
    }
  }
}
客户端
public class Client {
  public static void main(String[] args) {
    //定义多个构件并组合成树形结构
    Component root = new Composite("C盘");
    Component dir1 = new Composite("目录1");
    Component dir2 = new Composite("目录2");
    Component dir11 = new Composite("目录11");
    Component file1 = new Leaf("文件1");
    Component file2 = new Leaf("文件2");
    dir1.addChild(dir11);
    dir11.addChild(file1);
    dir2.addChild(file2);
    root.addChild(dir1);
    root.addChild(dir2);
    root.operation();
    System.out.println("==========");
    root.removeChild(dir1);
    root.operation();
    System.out.println("==========");
    root.getChild(0).operation();
  }
}
组成的树形结构为

安全式和透明式
组合模式分为透明式的组合模式和安全式的组合模式。
- 透明式,抽象构件声明了子类中的所有方法,所以客户端不需要区分叶子对象和组合对象,对客户端来说是透明的,
 但叶子对象本来没有addChild(),removeChild()方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。
- 将管理子节点的方法转移到组合对象中,抽象构件和叶子节点中没有管理子节点的方法,这样就避免了上一种方式的安全性问题,
 但由于叶子节点对象和组合对象有不同的接口,客户端需要区分这两种对象,所以失去了透明性。
上面的示例实现就是透明式,下面实现一下安全式。
public abstract class Component {
  protected String name;
  protected Component(String name) {
    this.name = name;
  }
  public abstract void operation();
}
客户端
public class Client {
  public static void main(String[] args) {
    //定义多个构件并组合成树形结构
    Composite root = new Composite("C盘");
    Composite dir1 = new Composite("目录1");
    Composite dir2 = new Composite("目录2");
    Composite dir11 = new Composite("目录11");
    Component file1 = new Leaf("文件1");
    Component file2 = new Leaf("文件2");
    dir1.addChild(dir11);
    dir11.addChild(file1);
    dir2.addChild(file2);
    root.addChild(dir1);
    root.addChild(dir2);
    root.operation();
    System.out.println("==========");
    root.removeChild(dir1);
    root.operation();
    System.out.println("==========");
    root.getChild(0).operation();
  }
}
叶子节点对象和组合对象都没有改变。
组合模式在Spring的实现
Spring中的CompositeIterator和CompositeCacheManager
 
 
Spring中很多地方都使用到了组合模式(安全式)。
总结
优点
- 简化了客户端调用,客户端不需要区分叶子对象和组合对象。
- 可以很方便的增加新的叶子对象或组合对象,符合开闭原则。
- 可以组成一个复杂的树形结构,并且很容易控制。
缺点
- 很难限制组合对象中的组件类型,例如限制某个文件夹对象中只能包含文本文件,这种情况就很难实现。
本质
组合模式的本质是统一叶子对象和组合对象。正因为统一了这两种类型的对象,才能组成复杂的树形结构。
使用场景
- 在具有整体和部分的层次结构中,希望统一这两种结构的操作。
参考
大战设计模式【13】—— 组合模式
设计模式的征途—9.组合(Composite)模式
设计模式(十)——组合模式(HashMap源码解析)
组合模式(详解版)
《JAVA设计模式》之组合模式(Composite)
研磨设计模式-书籍
 
         
         
         
         
         
        
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号