[把你的理性思维慢慢变成条件反射]
本文,我们讲介绍组合模式,文章主题结构与上文一致。惯例,先来看看我们示例工程的环境:
操作系统:win7 x64
其他软件:eclipse mars,jdk7
-------------------------------------------------------------------------------------------------------------------------------------
经典问题:
文件系统的目录结构,公司或政府部门的组织结构等具有树形递归关系的抽象组织结构。
思路分析:
要点一:每一级都可作为一个完整的最小树型结构。
要点二:每一级的外在表现类似,具有屏蔽层次结构的功能。如:文件系统不同级别的目录都具有相同的表现形式。分级行政办公组织结构中的相同部门设置。
要点三:对软件实现而言,需要尽可能的提高代码复用度。
示例工程:
组合模式模板代码【本例我们先展示模板代码,稍后演示一个具体的示例】
创建Component.java文件,具体内容如下:
package com.csdn.ingo.gof_Composite;
public abstract class Component{
protected String name;
public Component(String name){
this.name = name;
}
public abstract void add(Component c);
public abstract void remove(Component c);
public abstract void display(int depth);
}
创建Composite.java文件,具体内容如下:
package com.csdn.ingo.gof_Composite;
import java.util.ArrayList;
import java.util.List;
public class Composite extends Component {
private List<Component> children = new ArrayList<Component>();
public Composite(String name) {
super(name);
// TODO Auto-generated constructor stub
}
@Override
public void add(Component c) {
// TODO Auto-generated method stub
children.add(c);
}
@Override
public void remove(Component c) {
// TODO Auto-generated method stub
children.remove(c);
}
@Override
public void display(int depth) {
// TODO Auto-generated method stub
System.out.println("-"+name);
for(Component c:children){
c.display(depth+1);
}
}
}
创建Leaf.java文件,具体内容如下:
package com.csdn.ingo.gof_Composite;
public class Leaf extends Component{
public Leaf(String name) {
super(name);
}
@Override
public void add(Component c) {
// TODO Auto-generated method stub
System.out.println("cannot add to leaf");
}
@Override
public void remove(Component c) {
System.out.println("cannot remove from a leaf");
}
@Override
public void display(int depth) {
// TODO Auto-generated method stub
System.out.println(new String("----")+"depth:"+depth+"name:"+name);
}
}
创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_Composite;
public class Window {
public static void main(String[] args) {
Composite root = new Composite("root");
root.add(new Leaf("Leaf A"));
root.add(new Leaf("Leaf B"));
Composite comp = new Composite("ComposteX");
comp.add(new Leaf("Leaf XA"));
comp.add(new Leaf("Leaf XB"));
root.add(comp);
Composite comp2 = new Composite("ComposteXY");
comp2.add(new Leaf("Leaf XYA"));
comp2.add(new Leaf("Leaf XYB"));
comp.add(comp2);
root.add(new Leaf("Leaf C"));
Leaf l = new Leaf("Leaf D");
root.add(l);
root.remove(l);
root.display(1);
}
}
【上面的代码直接看的话,可能有难度。先把代码提供给各位看官是希望现将代码运行起来,观察结果。下面我们介绍相关的概念与原理】
模式总结:
组合模式结构图:
组合模式:
将对象组合成属性结构以表示“部分--整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
组成部分:
Component:抽象构件。可以是接口或者抽象类。其中包含leaf与composite公共接口的声明。如,增删改功能。
Leaf:叶子节点。其实就是最后一级节点,其下不能再有任何形式的impl或extend关系。其本身必须实现Component中定义的内容。
Composite:容器组件。是相对于Leaf定义的。其下还能够挂载其他的节点(可以是Leaf或Composite)。其中,可以通过递归实现对子部件的调用。
【以上,可以类比文件系统中的文件夹,文件夹可以包含文件或文件夹,文件本身不能包含其他文件或文件夹】
特别提示:上面的模板代码,在leaf与Composite中都包含了add和remove方法。但事实上,只有Composite的中的方法才是有效的。
实际场景用例:
需求描述:
公司包括:子公司,人力,研发,财务。子公司包括:子公司(可选的),人力,研发,财务。等等。
示例代码:
创建Company.java文件,具体内容如下:
package com.csdn.ingo.gof_Composite.one;
public abstract class Company{
protected String name;
public Company(String name){
this.name = name;
}
public abstract void add(Company c);
public abstract void remove(Company c);
public abstract void display(int depth);
public abstract void lineOfDuty();
}
创建ConcreteCompany.java文件,具体内容如下:
package com.csdn.ingo.gof_Composite.one;
import java.util.ArrayList;
import java.util.List;
public class ConcreteCompany extends Company {
private List<Company> children = new ArrayList<Company>();
public ConcreteCompany(String name) {
super(name);
// TODO Auto-generated constructor stub
}
@Override
public void add(Company c) {
// TODO Auto-generated method stub
children.add(c);
}
@Override
public void remove(Company c) {
// TODO Auto-generated method stub
children.remove(c);
}
@Override
public void display(int depth) {
// TODO Auto-generated method stub
System.out.println("-"+name);
for(Company c:children){
c.display(depth);
}
}
@Override
public void lineOfDuty() {
// TODO Auto-generated method stub
for(Company c:children){
c.lineOfDuty();
}
}
}
创建FinanceDepartment.java文件,具体内容如下:
package com.csdn.ingo.gof_Composite.one;
public class FinanceDepartment extends Company{
public FinanceDepartment(String name) {
super(name);
}
@Override
public void add(Company c) {
// TODO Auto-generated method stub
}
@Override
public void remove(Company c) {
// TODO Auto-generated method stub
}
@Override
public void display(int depth) {
// TODO Auto-generated method stub
System.out.println("----"+name);
}
@Override
public void lineOfDuty() {
// TODO Auto-generated method stub
System.out.println("finance duty:"+name);
}
}
创建HRDepartment.java文件,具体内容如下:
package com.csdn.ingo.gof_Composite.one;
public class HRDepartment extends Company{
public HRDepartment(String name) {
super(name);
}
@Override
public void add(Company c) {
// TODO Auto-generated method stub
}
@Override
public void remove(Company c) {
// TODO Auto-generated method stub
}
@Override
public void display(int depth) {
// TODO Auto-generated method stub
System.out.println("----"+name);
}
@Override
public void lineOfDuty() {
// TODO Auto-generated method stub
System.out.println("HR duty:"+name);
}
}
创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_Composite.one;
public class Window {
public static void main(String[] args) {;
Company root = new ConcreteCompany("总公司");
root.add(new HRDepartment("总公司人力资源部"));
root.add(new FinanceDepartment("总公司财务部"));
ConcreteCompany comp1 = new ConcreteCompany("上海分公司");
comp1.add(new HRDepartment("上海分公司人力资源部"));
comp1.add(new FinanceDepartment("上海分公司财务部"));
root.add(comp1);
ConcreteCompany comp2 = new ConcreteCompany("南京分公司");
comp2.add(new HRDepartment("南京分公司人力资源部"));
comp2.add(new FinanceDepartment("南京分公司财务部"));
root.add(comp2);
root.display(1);
root.lineOfDuty();
}
}
注:与模板代码对比,这里root对象也可以是抽象类Company。但,具体组织需要特别声明为具体实现。
模式扩展:
在上文中,我们说只有composite中的add和remove是有效的。
事实上,这些方法的设置在组合模式中成为透明组合模式,安全组合模式。即,在透明组合模式中,这些方法不区分leaf与composite。具体应用时可以通过返回值的变化或异常信息返回。而,安全组合模式要求父类不提供该方法的声明,而是由composite进行声明,这样在Window主类中就需要区别声明leaf与composite两个对象。
反思:
应用场景:
- 具有整体与部分的树形层次结构关系时,希望通过相同的结构屏蔽层次之间的差异性。
- 不同树形层次的功能具有类似性,并且希望达到重用的目的。
- 层次关系是不固定的,需要按照需求修改。
优点:
- 组合模式能够清楚的定义出复杂的关系。并且向客户端屏蔽了这种复杂与差异性。
- 客户端使用树形结构中的任何一个关系,可以通过一个统一的接口。有效减少客户端的依赖程度。
- 对树形结构的调整非常方便。而树形结构本身可能是非常复杂的。
缺点:
- 对于树形层次的约束不够。如,在组织关系处理中,子公司内不需要设置***部,但由于没有强制的约束条件,客户端可以随意修改。
-------------------------------------------------------------------------------------------------------------------------------------
至此,被说了很多遍的设计模式---组合模式 结束
参考资料:
图书:《大话设计模式》
其他博文:http://blog.csdn.NET/lovelion/article/details/7563445