软件设计模式修炼 -- 组合模式


组合模式关注那些存在于叶子构件和容器构件的结构以及它们的组织形式,叶子构件中不能包含成员对象,容器构件中能够包含成员对象,这些成员对象多是叶子构件对象,也多是容器构件对象。这些对象能够构成一个树形结构,组合模式是用面向对象的方法处理树形结构。java


模式动机

在Windows操做系统的文件目录结构包含文件和文件夹两类对象,其中在文件夹能够包含子文件夹,也能够包含文件。文件夹是容器类,而不一样类型的各类文件是成员类,也称为叶子类,一个文件夹也能够做为另外一个更大的文件夹的成员。组合模式描述了如何将容器对象和叶子对象进行递归组合,使得用户在使用时无须对它们进行区分,能够作到一致对待容器对象和叶子对象。算法


模式定义

组合多个对象造成树形结构以表示“总体-部分”的结构层次。编程


模式结构

在这里插入图片描述

  1. Component(抽象构件)安全

    抽象构件能够是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中能够包含全部子类共有行为的声明和实现。在抽象构件在定义了访问及管理它的子构件的方法,如增长子构件、删除子构件、获取子构件等。ide

  2. Leaf(叶子构件)操作系统

    叶子构件在组合结构中表示叶子节点对象,叶子节点没有子节点,实如今抽象构件中定义的行为。对于访问及管理子构件的方法,能够经过异常等方式进行处理。设计

  3. Composite(容器构件)code

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

  4. Client(客户类)blog

    客户类是能够经过抽象构件接口访问和控制组合构件中的对象。


模式分析

组合模式的关键是定义一个抽象构件类,它既能够表明叶子,也能够表明容器,而客户端针对该抽象构件类进行编程,无须知道它究竟是叶子仍是容器,能够对其进行统一处理。

通常抽象构件类设计为接口或抽象类,将全部子类共有方法声明和实现放在抽象构件类中。对于客户端编程,将针对抽象构件编程,而无须关心其具体子类是容器构件仍是叶子构件。

public abstract class Component {

    public abstract void add(Component c);
    public abstract void remove(Component c);
    public abstract Component getChild(int i);
    public abstract void operation();
}

继承抽象构件的是叶子构件则典型代码以下,叶子构件须要实现抽象构建类中声明的全部方法,包括业务方法以及管理和访问子构件的方法,可是叶子构件不包含子构件,所以在在客户端调用叶子构件的子构件管理和访问方法时需提供异常处理或错误提示。

public class Leaf extends Component {

    @Override
    public void add(Component c) {
        //异常处理或错误提示
    }

    @Override
    public void remove(Component c) {
        //异常处理或错误提示
    }

    @Override
    public Component getChild(int i) {
        //异常处理或错误提示
        return null;
    }

    @Override
    public void operation() {
        //实现代码
    }
}

容器构件须要实现抽象构建类中声明的全部方法,包括具体实现业务方法以及管理和访问子构件的方法。因为容器构件充当的是容器角色,包含成员构件,所以它将调用其成员构件的业务方法,使用递归算法,即在容器构件的operation()方法中递归调用其成员构件的operation()方法。

public class Composite extends Component {

    private ArrayList list = new ArrayList();

    @Override
    public void add(Component c) {
        list.add(c);
    }

    @Override
    public void remove(Component c) {
        list.remove(c);
    }

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

    @Override
    public void operation() {
        for (Object o : list) {
            ((Component) o).operation();
        }
    }
}

模式优缺点

组合模式优势:

  1. 组合模式能够清楚地定义分层次的复杂对象,表示对象的所有或部分层次,方便对层次结构进行控制
  2. 客户端能够一致的适用组合结构或其中单个对象,用户没必要关心本身处理的是单个对象仍是整个组合结构
  3. 定义了包含叶子对象和容器对象的类的层次结构,叶子对象能够被组合成更复杂的容器对象,而这个容器对象又能够被组合,这样不断递归下去,能够造成复杂的树形结构
  4. 更容易在组合体内加入对象构件,客户端没必要由于加入新的对象构件而更改原有代码

组合模式缺点:

  1. 使设计变得更加抽象
  2. 增长新构件时可能会产生一些问题,很难对容器中的构件类型进行限制

模式适用环境

在如下状况下可使用组合模式:

  1. 须要表示一个对象总体或部分层次,在具备总体和部分的层次结构中,但愿忽略总体与部分的差别,一致地对待它们
  2. 客户能忽略不一样对象层次的变化,客户端能够针对抽象构件编程,无须关心对象层次结构的细节
  3. 对象的结构是动态且复杂程度不一致,但客户须要一致地处理它们

透明组合模式与安全组合模式

组合模式根据抽象构件类的定义形式,又可分为透明组合模式和安全组合模式

  1. 透明组合模式

    透明组合模式中,抽象构件Component中声明全部用于管理成员对象的方法,这样作的好处是确保全部构件类都有相同的接口。在客户端看来,叶子对象与容器对象所提供的方法是一致的,客户端能够相同地对待全部的对象。缺点是不够安全,由于叶子对象和容器对象在本质上是有区别的。

  2. 安全组合模式

    安全组合模式中抽象构件Component中没有声明任何用于管理成员对象的方法,而是在Composite类中声明这些用于管理成员对象的方法。对于叶子对象,客户端不可能调用到管理成员对象的方法。缺点是不够透明,客户端不能彻底针对抽象编程。

相关文章
相关标签/搜索