设计模式 - 组合模式(Composite)

定义

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

类型

结构性模式

适用性

以下情况适用组合(Composite)模式:

  1. 当希望表示对象的整体-部分层次结构时;
  2. 当希望用户忽略组合对象和单个对象的不同,用户将统一的使用组合结构中的所有对象时;

结构

组合模式结构

参与者

抽象组件(Component): 可以是接口或抽象类,为叶子组件(Leaf)和容器组件(Composite)声明接口;在适当的情况下,实现所有类共有接口的缺省行为;同时定义了访问及管理它的子构件的方法,如增加子组件、删除子组件、获取子组件等。

叶子组件(Leaf): 在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象组件(Component)中定义的行为。

容器组件(Composite): 在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。

客户端(Client): 通过抽象组件接口操纵组合部件的对象。

优缺点

优点

(1)组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。

(2)客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。

(3)在组合模式中增加新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改,符合“开闭原则”。

(4)组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

缺点

在增加新构件时很难对容器中的构件类型进行限制。有时候我们希望一个容器中只能有某些特定类型的对象,例如在某个文件夹中只能包含文本文件,使用组合模式时,不能依赖类型系统来施加这些约束,因为它们都来自于相同的抽象层,在这种情况下,必须通过在运行时进行类型检查来实现,这个实现过程较为复杂。

组合模式实现

抽象组件(Component)

public interface Component {
    void print();

    void add(Component component);

    void remove(Component component);

    Component getChild(int i);
}

容器组件(Composite)

public class Composite implements Component {

    private List<Component> childCompanies = new ArrayList<Component>();

    @Override
    public void print() {
        childCompanies.forEach(Component::print);
    }

    @Override
    public void add(Component component) {
        childCompanies.add(component);
    }

    @Override
    public void remove(Component component) {
        childCompanies.remove(component);
    }

    @Override
    public Component getChild(int i) {
        return this.childCompanies.get(i);
    }
}

叶子组件(Leaf)

public class Leaf implements Component {
    @Override
    public void print() {
        System.out.println("Leaf");
    }

    @Override
    public void add(Component component) throws UnsupportedOperationException {
        throw new UnsupportedOperationException("Unsuppoer add operation with Leaf obj");
    }

    @Override
    public void remove(Component component) {
        throw new UnsupportedOperationException("Unsuppoer remove operation with Leaf obj");
    }

    @Override
    public Component getChild(int i) {
        throw new UnsupportedOperationException("Unsuppoer getChild operation with Leaf obj");
    }
}

客户端(Client)

public class Client {
    public static void main(String[] args) {
        new Client().test();
    }

    private void test() {
        Leaf leaf1 = new Leaf();
        Leaf leaf2 = new Leaf();
        Leaf leaf3 = new Leaf();
        Leaf leaf4 = new Leaf();

        Component composite = new Composite();

        Component composite1 = new Composite();
        Component composite2 = new Composite();

        composite1.add(leaf1);
        composite1.add(leaf2);
        composite2.add(leaf3);

        composite2.add(leaf4);

        composite.add(composite1);
        composite.add(composite2);

        composite.print();
    }
}

参考代码

https://github.com/xueyufish/design-pattern-java/tree/master/composite