一、概述
允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及组合对象。
二、解决问题
组合模式解决这样的问题,当我们的要处理的对象可以生成一颗树形结构,而我们要对树上的节点和叶子进行操作时,它能够提供一致的方式,而不用考虑它是节点还是叶子。
三、结构类图
四、应用实例
上一讲中,我们是以大学的院系结构来讲解迭代器的,在组合模式中,我们还是引用这个例子。把学校作为根节点,学院做普通节点,专业就是叶子。
首先,从上面的类图中知道,对于客户端来说,其需要面对的就是一个组件,而不用管是否节点还是叶子。我们就先来创建这样一个组件
package com.jet.pattern.Composite; /** * description: * 机构组件,学院和系称为机构 * Created by Administrator on 2016/11/17. */ public abstract class OrganizationComponent { // 每个方法提供默认的实现 public void add(OrganizationComponent organizationComponent){ throw new UnsupportedOperationException(); } public void remove(OrganizationComponent organizationComponent){ throw new UnsupportedOperationException(); } public String getName(){ throw new UnsupportedOperationException(); } public String getDescription(){ throw new UnsupportedOperationException(); } public void print(){ throw new UnsupportedOperationException(); } }
接着从上到下创建组件对象,创建学校对象
package com.jet.pattern.Composite.impl; import com.jet.pattern.Composite.OrganizationComponent; import java.util.ArrayList; import java.util.List; /** * description: * 大学对象 * Created by Administrator on 2017/1/13. */ public class University extends OrganizationComponent { String name; String description; List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>(); public University(String name, String description) { this.name = name; this.description = description; } // 重写机构组件的方法,其作为树有增加和删除方法 @Override public void add(OrganizationComponent organizationComponent) { organizationComponents.add(organizationComponent); } @Override public void remove(OrganizationComponent organizationComponent) { organizationComponents.remove(organizationComponent); } @Override public String getName() { return name; } @Override public String getDescription() { return description; } @Override public void print() { System.out.println("-------" + getName() + "-----------"); // 大学下面有很多学院,把他们遍历出来 for(OrganizationComponent organizationComponent : organizationComponents){ organizationComponent.print(); } } }
创建学院对象
package com.jet.pattern.Composite.impl; import com.jet.pattern.Composite.OrganizationComponent; import java.util.ArrayList; import java.util.List; /** * description: * 学院是一个机构, * Created by Administrator on 2017/1/13. */ public class College extends OrganizationComponent { String name; String description; List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>(); public College(String name, String description) { this.name = name; this.description = description; } // 重写机构组件的方法,其作为树有增加和删除方法 @Override public void add(OrganizationComponent organizationComponent) { organizationComponents.add(organizationComponent); } @Override public void remove(OrganizationComponent organizationComponent) { organizationComponents.remove(organizationComponent); } @Override public String getName() { return name; } @Override public String getDescription() { return description; } @Override public void print() { System.out.println("-------" + getName() + "-----------"); // 学院下面有很多专业,把他们遍历出来 for(OrganizationComponent organizationComponent : organizationComponents){ organizationComponent.print(); } } }
创建专业(系)对象
package com.jet.pattern.Composite.impl; import com.jet.pattern.Composite.OrganizationComponent; /** * description: * 专业(系)对象 * Created by Administrator on 2017/1/13. */ public class Department extends OrganizationComponent { String name; String description; public Department(String name, String description) { this.name = name; this.description = description; } // 重写机构组件的方法,其作为叶子没有增加和删除方法 @Override public String getName() { return name; } @Override public String getDescription() { return description; } // 叶子只需要输出自己的信息 @Override public void print() { System.out.println(getName()); } }
创建输出对象,模拟客户端
package com.jet.pattern.Composite.impl; import com.jet.pattern.Composite.OrganizationComponent; /** * description: * 输出信息,模拟客户调用 * Created by Administrator on 2017/1/13. */ public class OutputInfo { OrganizationComponent allOrganization; public OutputInfo(OrganizationComponent allOrganization) { this.allOrganization = allOrganization; } public void printOrganization(){ allOrganization.print(); } }
测试组合模式
package com.jet.pattern.Composite.test; import com.jet.pattern.Composite.OrganizationComponent; import com.jet.pattern.Composite.impl.College; import com.jet.pattern.Composite.impl.Department; import com.jet.pattern.Composite.impl.OutputInfo; import com.jet.pattern.Composite.impl.University; /** * description: * 测试组合模式 * Created by Administrator on 2017/1/13. */ public class CompositeTest { public static void main(String[] args) { // 从大到小创建对象,学院和专业组合成为学校,先创建学校,它也是机构组件 OrganizationComponent university = new University("清华大学","全国最好的大学"); // 接着创建学院 OrganizationComponent computerCollege = new College("计算机学院","计算机学院"); OrganizationComponent infoEngineeringCollege = new College("信息工程学院","信息工程学院"); // 计算机学院有下面专业 computerCollege.add(new Department("计算机科学与技术","计算机科学与技术")); computerCollege.add(new Department("软件工程 ","软件工程")); computerCollege.add(new Department("网络工程","网络工程")); // 信息工程学院有下面专业 infoEngineeringCollege.add(new Department("通信工程","通信工程")); infoEngineeringCollege.add(new Department("信息工程","信息工程")); // 学校有下面学院 university.add(computerCollege); university.add(infoEngineeringCollege); // 输出学校机构信息 OutputInfo info = new OutputInfo(university); info.printOrganization(); } }
测试输出结果如下:
五、使用场景
1.当需要遍历组织机构,或者处理的对象具有树形结构时使用。
六、优缺点
1.优点
(1)、简化客户端操作。客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子的问题。
(2)、具有较强的扩展性。当我们要更改组合对象时,我们只需要调整内部的层次关系,客户端不用做出任何改动。
(3)、方便创建出复杂的层次结构。客户端不用理会组合里面的组成细节,容易添加节点或者叶子从而创建出复杂的树形结构。
2.缺点
(1)、要求较高的抽象性,如果节点和叶子有很多差异性的话,比如很多方法和属性都不一样,难以实现组合模式。