定义:允许你将对象组合成树形结构来表现 "整体 - 部分" 层次结构。 组合能让客户以一致的方法处理个别对象以及组合对象。
主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
英文:Composite
类型:结构型
(引)类图:
组成:
●Component(抽象构件):接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的缺省声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。
●Composite(容器构件):容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。
● Leaf(叶子构件):
,不再包含其它的子节点对象。
- 叶子节点对象,定义和实现叶子对象的行为
PS: 组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。
代码结构:
- /**
- * 抽象构件角色: 抽象的组件对象,为组合中的对象声明接口,实现接口的缺省行为
- */
- public abstract class Component {
- /**
- * 向组合对象中加入组件对象
- * @param child 被加入组合对象中的组件对象
- */
- public void add(Component child) {
- // 缺省的实现,抛出例外,因为叶子对象没有这个功能,
- //或者子组件没有实现这个功能
- throw new UnsupportedOperationException("对象不支持这个功能");
- }
- /**
- * 从组合对象中移出某个组件对象
- * @param child 被移出的组件对象
- */
- public void remove(Component child) {
- // 缺省的实现,抛出例外,因为叶子对象没有这个功能,
- //或者子组件没有实现这个功能
- throw new UnsupportedOperationException("对象不支持这个功能");
- }
- /**
- * 返回某个索引对应的组件对象
- * @param index 需要获取的组件对象的索引,索引从0开始
- * @return 索引对应的组件对象
- */
- public Component getChild(int index) {
- // 缺省的实现,抛出例外,因为叶子对象没有这个功能,
- //或者子组件没有实现这个功能
- throw new UnsupportedOperationException("对象不支持这个功能");
- }
- /**
- * 示意方法,子组件对象可能有的功能方法
- */
- public abstract void operation();
- }
- /**
- * 容器构件:组合对象,通常需要存储子对象,定义有子部件的部件行为,并实现在Component里面定义的与子部件有关的操作
- */
- public class Composite extends Component {
- /**
- * 用来存储组合对象中包含的子组件对象
- */
- private List childComponents = null;
- public void add(Component child) {
- //延迟初始化
- if (childComponents == null) {
- childComponents = new ArrayList();
- }
- childComponents.add(child);
- }
- public void remove(Component child) {
- if (childComponents != null) {
- childComponents.remove(child);
- }
- }
- public Component getChild(int index) {
- if (childComponents != null) {
- if (index >= 0 && index < childComponents.size()) {
- return childComponents.get(index);
- }
- }
- return null;
- }
- /**
- * 示意方法,通常在里面需要实现递归的调用
- */
- public void operation() {
- if (childComponents != null) {
- for (Component c: childComponents) {
- //递归的进行子组件相应方法的调用
- c.operation();
- }
- }
- }
- }
- /**
- * 叶子构件:叶子对象,叶子对象不再包含其它子对象
- */
- public class Leaf extends Component {
- /**
- * 示意方法,叶子对象可能有自己的功能方法
- */
- public void operation() {
- // do something
- }
- }
我们用组合模式实现简单的组织架构:
+ 吊炸天股份有限公司
+ 北京分公司
- 研发部
- 市场部
- 省略...
+ 上海分公司
- 市场部
- 销售部
- 省略...
- package com.designpattern.Composite;
- /**
- * 抽象构件角色
- * @author Json<<json1990@foxmail.com>>
- */
- public abstract class Component {
- /**
- * 向组合对象中加入组件对象
- * @param child 被加入组合对象中的组件对象
- */
- public void add(Component child) {
- throw new UnsupportedOperationException("对象不支持这个功能");
- }
- /**
- * 从组合对象中移出某个组件对象
- * @param child 被移出的组件对象
- */
- public void remove(Component child) {
- throw new UnsupportedOperationException("对象不支持这个功能");
- }
- /**
- * 返回某个索引对应的组件对象
- * @param index 需要获取的组件对象的索引,索引从0开始
- * @return 索引对应的组件对象
- */
- public Component getChild(int index) {
- throw new UnsupportedOperationException("对象不支持这个功能");
- }
- /**
- * 输出组件自身的名称
- */
- public abstract void outputSelf(String str);
- }
- package com.designpattern.Composite;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * 容器构件
- * @author Json<<json1990@foxmail.com>>
- */
- public class Composite extends Component {
- /**
- * 用来存储组合对象中包含的子组件对象
- */
- private List childComponents = null;
- /**
- * 组合对象的名字
- */
- private String name = "";
- /**
- * 构造方法,传入组合对象的名字
- * @param name 组合对象的名字
- */
- public Composite(String name) {
- this.name = name;
- }
- /**
- * 向组合对象中加入组件对象
- * @param child 被加入组合对象中的组件对象
- */
- public void add(Component child) {
- //延迟初始化
- if (childComponents == null) {
- childComponents = new ArrayList();
- }
- childComponents.add(child);
- }
- /**
- * 从组合对象中移出某个组件对象
- * @param child 被移出的组件对象
- */
- public void remove(Component child) {
- if (childComponents != null) {
- childComponents.remove(child);
- }
- }
- /**
- * 输出组合对象自身的结构
- * @param str 前缀,主要是按照层级拼接的空格,实现向后缩进
- */
- @Override public void outputSelf(String str) {
- //先把自己输出去
- System.out.println(str + "+ " + this.name);
- //如果还包含有子组件,那么就输出这些子组件对象
- if (this.childComponents != null) {
- //添加若干空格,表示向后缩进若干空格
- str += " ";
- //输出当前对象的子对象了
- for (Component c: childComponents) {
- //递归输出每个子对象
- c.outputSelf(str);
- }
- }
- }
- }
- package com.designpattern.Composite;
- /**
- * 叶子
- * @author Json<<json1990@foxmail.com>>
- */
- public class Leaf extends Component {
- /**
- * 叶子对象的名字
- */
- private String name = "";
- /**
- * 构造方法,传入叶子对象的名字
- * @param name 叶子对象的名字
- */
- public Leaf(String name) {
- this.name = name;
- }
- /**
- * 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字
- * @param str 前缀,主要是按照层级拼接的空格,实现向后缩进
- */
- public void outputSelf(String str) {
- System.out.println(str + "- " + name);
- }
- }
测试:
- package com.designpattern.Composite;
- /**
- * 测试
- * @author Json<<json1990@foxmail.com>>
- */
- public class Client {
- public static void main(String[] args) {
- //定义所有的组合对象
- Composite root = new Composite("吊炸天股份有限公司");
- Composite c1 = new Composite("北京分公司");
- Composite c2 = new Composite("上海分公司");
- //定义所有的叶子对象
- Leaf leaf1_1 = new Leaf("研发部");
- Leaf leaf1_2 = new Leaf("市场部");
- Leaf leaf1_3 = new Leaf("省略...");
- Leaf leaf2_1 = new Leaf("市场部");
- Leaf leaf2_2 = new Leaf("销售部");
- Leaf leaf2_3 = new Leaf("省略...");
- //按照树的结构来组合组合对象和叶子对象
- root.add(c1);
- c1.add(leaf1_1);
- c1.add(leaf1_2);
- c1.add(leaf1_3);
- root.add(c2);
- c2.add(leaf2_1);
- c2.add(leaf2_2);
- c2.add(leaf2_3);
- //调用根对象的输出功能来输出整棵树
- root.outputSelf("");
- System.out.println("--------删除节点(上海分公司撤销了)↓↓↓----------");
- root.remove(c2);
- root.outputSelf("");
- }
- }
结果:
- + 吊炸天股份有限公司 + 北京分公司 - 研发部 - 市场部 - 省略... + 上海分公司 - 市场部 - 销售部 - 省略...--------删除节点(上海分公司撤销了)↓↓↓----------+吊炸天股份有限公司 + 北京分公司 - 研发部 - 市场部 - 省略...
PS:上面的例子很简单,只是实现了基本功能,在实际开发中可能遇到的情景,会比这个复杂,这里要明白组合模式的原理,化有形为无形,做到手中无剑,心中有剑;
1、 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
2、 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
3、 在组合模式中增加新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改,符合 "开闭原则"。
4、 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。
在增加新构件时很难对容器中的构件类型进行限制。有时候我们希望一个容器中只能有某些特定类型的对象,例如在某个文件夹中只能包含文本文件,使用组合模式时,不能依赖类型系统来施加这些约束,因为它们都来自于相同的抽象层,在这种情况下,必须通过在运行时进行类型检查来实现,这个实现过程较为复杂。
1、 在对象具有部分 - 整体层次结构,可以选用组合模式,把整体和部分的操作统一起来,使得层次结构实现更简单,从外部来使用这个层次结构也简单。
2、 系统中需要处理一个树形结构。
3、 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新的类型。
4、 想统一的使用组合结构中的所有对象,可以选用组合模式,这正是组合模式提供的主要功能。
实际应用:
XML 解析
组织结构树处理
文件系统设计
......
组合模式并不难理解,它主要解决的是单一对象和组合对象在使用方式上的一致性问题。如果对象具有明显的层次结构并且想要统一地使用它们,这就非常适合使用组合模式。在 web 开发中,这种层次结构非常常见,很适合使用组合模式,达到对部分和整体使用的一致性。
PS:源码地址 https://github.com/JsonShare/DesignPattern/tree/master
来源: http://www.cnblogs.com/JsonShare/p/7239560.html