说明:设计模式系列文章是读刘伟所著《设计模式的艺术之道(软件开发人员内功修炼之道)》一书的阅读笔记。个人感觉这本书讲的不错,有兴趣推荐读一读。详细内容也可以看看此书作者的博客https://blog.csdn.net/LoveLion/article/details/17517213
模式概述树形结构在软件中随处可见,例如操作系统中的目录结构、应用软件中的菜单、办公系统中的公司组织结构等等,如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题。组合模式通过一种巧妙的设计方案使得用户可以一致性地处理整个树形结构或者树形结构的一部分,也可以一致性地处理树形结构中的叶子节点(不包含子节点的节点)和容器节点(包含子节点的节点)。
模式定义组合模式(Composite Pattern):组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。
模式结构图组合模式结构图如下所示:
在组合模式结构图中包含如下几个角色:
Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。
Leaf(叶子构件):它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。
Composite(容器构件):它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。
组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。
模式伪代码对于客户端而言,一般针对抽象构件编程,而无须关心其具体子类是容器构件还是叶子构件。抽象构建类典型代码如下:
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() { //叶子构件具体业务方法的实现 } }如果继承抽象构件的是容器构件,则其典型代码如下所示:
public class Composite extends Component { private List<Component> 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 obj : list) { ((Component) obj).operation(); } } }客户端对抽象构件类进行编程
public class Client { public static void main(String[] args) { Component component; component = new Leaf(); //component = new Composite(); // 无须知道到底是叶子还是容器 // 可以对其进行统一处理 component.operation(); } } 模式简化 透明组合模式透明组合模式中,抽象构件Component中声明了所有用于管理成员对象的方法,包括add()、remove()以及getChild()等方法,这样做的好处是确保所有的构件类都有相同的接口。在客户端看来,叶子对象与容器对象所提供的方法是一致的,客户端可以相同地对待所有的对象。透明组合模式也是组合模式的标准形式。
透明组合模式的完整结构图如下: