设计模式之组合模式
1 概述
组合模式(Composite),将对象组合成树形结构来表现“整体&部分”这一层次结构。这种模式能让客户以一致的方式处理个别对象以及对象组合。
组合内的所有对象都必须实现相同的接口,当组合结构复杂,遍历的成本太高时,就有必要实现组合节点的缓存。组合的优点是可以让客户端不再区分操作的是组合对象还是叶子对象,而是以一种统一的方式来操作。
组合模式的组成部分有以下三个:
(1)抽象构件角色(Component):是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。这个接口可以用来管理所有的子对象。
(2)树枝构件角色(Composite):定义有子部件的那些部件的行为。在Component接口中实现与子部件有关的操作,构件和构件之间是可以嵌套的。
(3)树叶构件角色(Leaf):在组合树中表示叶节点对象,叶节点没有子节点。并在组合中定义图元对象的行为。
(4)客户角色(Client):通过component接口操纵组合部件的对象。
2 示例
通常公司的组织形式就是一种组合模式,一个公司的抽象就是个Component,具体的公司来继承这个抽象类就是Composite,公司下面可以是有子公司,而每个公司又可以有很多部门,每个部门都是叶子Leaf。
同样,电脑中的文件和目录也是一种组合模式,每个具体的目录Directory都是Composite,目录下面可以有很多子录,也可以放很多文件,文件就是树叶Leaf。
更直观的例子,菜单,不同的菜单可以嵌套,最底层就是各个菜单选项。
下面以公司的组织形式为例。
阿里巴巴集团下面很多子公司,阿里妈妈、淘宝、天猫、阿里云等等,每个公司都有自己的部门和主要提供的服务,比如阿里巴巴主要提供B2B,淘宝主要是C2C,天猫主要是C2C,阿里云就是云计算服务了。每个公司都是独立的子公司,所以也就有着自己的研发部门、人力资源部门、市场部门等。
首先建立一个公司的抽象类,就是上面组成部分的“抽象构件”角色:
1 package org.scott.composite; 2 /** 3 * @author Scott 4 * @date 2013年12月12日 5 * @description 6 */ 7 public abstract class Company { 8 public abstract void display(int depth); 9 10 public void add(Company company){ 11 12 }; 13 14 public void remove(Company company){ 15 16 }; 17 }
下面就是具体的公司类了,就是上面组成部分的“树枝构件”角色:
1 package org.scott.composite; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 /** 7 * @author Scott 8 * @date 2013年12月12日 9 * @description 10 */ 11 public class ConcreteCompany extends Company { 12 private String name; 13 private String product; 14 private List<Company> companyList; 15 16 public String getName() { 17 return name; 18 } 19 20 public String getProduct() { 21 return product; 22 } 23 24 public ConcreteCompany(String name, String product){ 25 this.name = name; 26 this.product = product; 27 companyList = new ArrayList<Company>(); 28 } 29 30 @Override 31 public void display(int depth) { 32 StringBuffer strBuf = new StringBuffer(""); 33 for (int i = 0; i < depth; i++) { 34 strBuf.append("--"); 35 } 36 37 System.out.println(new String(strBuf) + this.getName()); 38 System.out.println(" The major service is " + this.getProduct()); 39 40 for (Company c : companyList) { 41 c.display(depth + 2); 42 } 43 } 44 45 @Override 46 public void add(Company company) { 47 this.companyList.add(company); 48 } 49 50 @Override 51 public void remove(Company company) { 52 this.companyList.remove(company); 53 } 54 }
此处的代码第41行:
41 c.display(depth + 2);
之所加2,是因为在这个例子中,我们的组织结构是公司+部门这两层,要把公司到部门的所有信息都打印出来,所以到了子公司这一层,层数就得+2了。
接着就是部门了,即概述中组成部分的“树叶”角色:
1 package org.scott.composite; 2 /** 3 * @author Scott 4 * @date 2013年12月12日 5 * @description 6 */ 7 public class Department extends Company { 8 private String name; 9 10 public String getName() { 11 return name; 12 } 13 14 public Department(String name){ 15 this.name = name; 16 } 17 18 @Override 19 public void display(int depth) { 20 StringBuilder sb = new StringBuilder(""); 21 for (int i = 0; i < depth; i++) { 22 sb.append("--"); 23 } 24 System.out.println(new String(sb) + this.getName() ) ; 25 } 26 27 @Override 28 public void add(Company company) { 29 30 } 31 32 @Override 33 public void remove(Company company) { 34 35 } 36 37 }
来个测试类,组织一下阿里的公司架构:
1 package org.scott.composite; 2 /** 3 * @author Scott 4 * @date 2013年12月12日 5 * @description 6 */ 7 public class CompositeTest { 8 9 public static void main(String[] args) { 10 Company alibaba = new ConcreteCompany("Alibaba", "B2B"); 11 Company taobao = new ConcreteCompany("Taobao", "C2C"); 12 Company aliyun = new ConcreteCompany("Aliyun", "Cloud Compution"); 13 14 Company aliHrDepartment = new Department("Alibaba HR Department"); 15 Company aliResearchDepartment = new Department("Alibaba RESEARCH Department"); 16 Company taobaoHrDepartment = new Department("Taobao HR Department"); 17 Company taobaoResearchDepartment = new Department("Taobao RESEARCH Department"); 18 Company aliyunHrDepartment = new Department("Aliyun HR Department"); 19 Company aliyunResearchDepartment = new Department("Aliyun RESEARCH Department"); 20 21 alibaba.add(taobao); 22 alibaba.add(aliyun); 23 alibaba.add(aliHrDepartment); 24 alibaba.add(aliResearchDepartment); 25 26 taobao.add(taobaoHrDepartment); 27 taobao.add(taobaoResearchDepartment); 28 29 aliyun.add(aliyunHrDepartment); 30 aliyun.add(aliyunResearchDepartment); 31 32 alibaba.display(0); 33 System.out.println("\n~~~~~~~~~~~~~~~~~~~~~~~~\n"); 34 taobao.display(0); 35 System.out.println("\n~~~~~~~~~~~~~~~~~~~~~~~~\n"); 36 aliyun.display(0); 37 } 38 39 }
测试类中有三个公司,阿里巴巴、淘宝、阿里云,其中,淘宝和阿里云是阿里巴巴的子公司,同时,每个公司又有自己的研发部门和人资部门。
运行结果:
Alibaba The major service is B2B ----Taobao The major service is C2C --------Taobao HR Department --------Taobao RESEARCH Department ----Aliyun The major service is Cloud Compution --------Aliyun HR Department --------Aliyun RESEARCH Department ----Alibaba HR Department ----Alibaba RESEARCH Department ~~~~~~~~~~~~~~~~~~~~~~~~ Taobao The major service is C2C ----Taobao HR Department ----Taobao RESEARCH Department ~~~~~~~~~~~~~~~~~~~~~~~~ Aliyun The major service is Cloud Compution ----Aliyun HR Department ----Aliyun RESEARCH Department
上个网上经典的组合模式的类图吧: