组合模式:允许你将对象组合成树型结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合.
Composite模式涉及的是一组对象,其中有些对象可能含有其他的对象;因此,有些对象可能代表一个对象群组,而其他的则是单个对象,即叶子。利用Composite模式建模包含两个重要的建模概念。其中一个重要的思想是所设计的群组即能包含单个个体,还要能包含其他群组(一个常见的错误是所设计的群组只能包含叶子)。另一个重要的概念是要定义出单个对象和对象组合的公共特性。结合这两个概念,我们可以定义即适合群组又适合单个个体的通用类型,然后将群组建模成具有这种类型的对象的集合。
Composite模式的设计意图在于:让用户能够用统一的接口处理单个对象以及对象组合.
组合模式的组成部份:
1.抽象组件
2.组件节点
3.叶节点
组合模式的各组成部份之间的关系:
例子:
抽象组件:
package composite;
import java.util.Iterator;
/** *//**
* <ul>
* <li>Title:[MilitaryPerson]</li>
* <li>Description: [军人抽象组件]</li>
* <li>Copyright 2009 Upengs Co., Ltd.</li>
* <li>All right reserved.</li>
* <li>Created by [Huyvanpull] [2011-8-2]</li>
* <li>Midified by [modifier] [modified time]</li>
* </ul>
*
* @version 1.0
*/
public interface MilitaryPerson
{
/** *//**
* <ul>
* <li>Description:[添加组件]</li>
* <li>Created by [Huyvanpull] [2011-8-2]</li>
* <li>Midified by [modifier] [modified time]</li>
* </ul>
*
* @param person
*/
public void add(MilitaryPerson person);
/** *//**
* <ul>
* <li>Description:[删除组件]</li>
* <li>Created by [Huyvanpull] [2011-8-2]</li>
* <li>Midified by [modifier] [modified time]</li>
* </ul>
*
* @param person
*/
public void remove(MilitaryPerson person);
/** *//**
* <ul>
* <li>Description:[得到子节点]</li>
* <li>Created by [Huyvanpull] [2011-8-2]</li>
* <li>Midified by [modifier] [modified time]</li>
* </ul>
*
* @param index
* @return
*/
public MilitaryPerson getChild(int index);
/** *//**
* <ul>
* <li>Description:[得到所有节点]</li>
* <li>Created by [Huyvanpull] [2011-8-2]</li>
* <li>Midified by [modifier] [modified time]</li>
* </ul>
*
* @return
*/
public Iterator<MilitaryPerson> getAllChildren();
/** *//**
* <ul>
* <li>Description:[是否叶节点]</li>
* <li>Created by [Huyvanpull] [2011-8-2]</li>
* <li>Midified by [modifier] [modified time]</li>
* </ul>
*
* @return
*/
public boolean isLeaf();
/** *//**
* <ul>
* <li>Description:[得到薪水]</li>
* <li>Created by [Huyvanpull] [2011-8-2]</li>
* <li>Midified by [modifier] [modified time]</li>
* </ul>
*
* @return
*/
public double getSalary();
/** *//**
* <ul>
* <li>Description:[设置薪水]</li>
* <li>Created by [Huyvanpull] [2011-8-2]</li>
* <li>Midified by [modifier] [modified time]</li>
* </ul>
*
* @param salary
* @return
*/
public double setSalary(double salary);
}
组件节点:
package composite;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/** *//**
* <ul>
* <li>Title:[MilitaryOfficer]</li>
* <li>Description: [军官]</li>
* <li>Copyright 2009 Upengs Co., Ltd.</li>
* <li>All right reserved.</li>
* <li>Created by [Huyvanpull] [2011-8-2]</li>
* <li>Midified by [modifier] [modified time]</li>
* </ul>
* @version 1.0
*/
public class MilitaryOfficer implements MilitaryPerson
{
/** *//** 姓名 */
public String name;
/** *//** 薪水 */
public double salary;
/** *//** 组件容器 */
private List<MilitaryPerson> militaryPersonLst;
/** *//**
*<ul>
*<li>Description:[构造方法]</li>
*<ul>
* @param name
* @param salary
*/
public MilitaryOfficer(String name, double salary)
{
this.name = name;
this.salary = salary;
this.militaryPersonLst = new ArrayList<MilitaryPerson>();
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#add(composite.MilitaryPerson)
*/
public void add(MilitaryPerson person)
{
this.militaryPersonLst.add(person);
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#getAllChildren()
*/
public Iterator<MilitaryPerson> getAllChildren()
{
return this.militaryPersonLst.iterator();
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#getChild(int)
*/
public MilitaryPerson getChild(int index)
{
return this.militaryPersonLst.get(index);
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#getSalary()
*/
public double getSalary()
{
return salary;
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#isLeaf()
*/
public boolean isLeaf()
{
return false;
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#remove(composite.MilitaryPerson)
*/
public void remove(MilitaryPerson person)
{
this.militaryPersonLst.remove(person);
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#setSalary(double)
*/
public double setSalary(double salary)
{
return salary;
}
}
叶结点:
package composite;
import java.util.Iterator;
/** *//**
* <ul>
* <li>Title:[MilitarySoldier]</li>
* <li>Description: [士兵]</li>
* <li>Copyright 2009 Upengs Co., Ltd.</li>
* <li>All right reserved.</li>
* <li>Created by [Huyvanpull] [2011-8-2]</li>
* <li>Midified by [modifier] [modified time]</li>
* </ul>
* @version 1.0
*/
public class MilitarySoldier implements MilitaryPerson
{
/** *//** 姓名 */
public String name;
/** *//** 薪水 */
public double salary;
/** *//**
*<ul>
*<li>Description:[构造方法]</li>
*<ul>
* @param name
* @param salary
*/
public MilitarySoldier(String name, double salary)
{
this.name = name;
this.salary = salary;
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#add(composite.MilitaryPerson)
*/
public void add(MilitaryPerson person)
{
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#getAllChildren()
*/
public Iterator<MilitaryPerson> getAllChildren()
{
return null;
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#getChild(int)
*/
public MilitaryPerson getChild(int index)
{
return null;
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#getSalary()
*/
public double getSalary()
{
return salary;
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#isLeaf()
*/
public boolean isLeaf()
{
return true;
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#remove(composite.MilitaryPerson)
*/
public void remove(MilitaryPerson person)
{
}
/**//* (non-Javadoc)
* @see composite.MilitaryPerson#setSalary(double)
*/
public double setSalary(double salary)
{
return salary;
}
}
计算程序(和模式无关的):
package composite;
import java.util.Iterator;
public class CalcSalary
{
/** *//**
* <ul>
* <li>Description:[计算薪水方法]</li>
* <li>Created by [Huyvanpull] [2011-8-2]</li>
* <li>Midified by [modifier] [modified time]</li>
* </ul>
* @param person
* @return
*/
public static double calcSalary(MilitaryPerson person)
{
double sumSalary = person.getSalary();
if (!person.isLeaf())
{
Iterator<MilitaryPerson> iterator = person.getAllChildren();
while (iterator.hasNext())
{
MilitaryPerson militaryPerson = iterator.next();
sumSalary += militaryPerson.getSalary();
}
}
return sumSalary;
}
}
测试:
package composite;
public class Test
{
public static void main(String[] args)
{
// 上将
MilitaryPerson general = new MilitaryOfficer("上将", 100000);
// 上校
MilitaryPerson colonel1 = new MilitaryOfficer("上校1", 80000);
MilitaryPerson colonel2 = new MilitaryOfficer("上校2", 80000);
general.add(colonel1);
general.add(colonel2);
// 上尉
MilitaryPerson captain1 = new MilitaryOfficer("上尉1", 60000);
MilitaryPerson captain2 = new MilitaryOfficer("上尉2", 60000);
colonel1.add(captain1);
colonel1.add(captain2);
MilitaryPerson captain3 = new MilitaryOfficer("上尉3", 60000);
MilitaryPerson captain4 = new MilitaryOfficer("上尉4", 60000);
colonel2.add(captain3);
colonel2.add(captain4);
// 士兵
MilitarySoldier airman1 = new MilitarySoldier("士兵", 10000);
MilitarySoldier airman2 = new MilitarySoldier("士兵", 10000);
MilitarySoldier airman3 = new MilitarySoldier("士兵", 10000);
captain1.add(airman1);
captain1.add(airman2);
captain1.add(airman3);
MilitarySoldier airman4 = new MilitarySoldier("士兵", 10000);
MilitarySoldier airman5 = new MilitarySoldier("士兵", 10000);
MilitarySoldier airman6 = new MilitarySoldier("士兵", 10000);
captain2.add(airman4);
captain2.add(airman5);
captain2.add(airman6);
MilitarySoldier airman7 = new MilitarySoldier("士兵", 10000);
MilitarySoldier airman8 = new MilitarySoldier("士兵", 10000);
MilitarySoldier airman9 = new MilitarySoldier("士兵", 10000);
captain3.add(airman7);
captain3.add(airman8);
captain3.add(airman9);
MilitarySoldier airman10 = new MilitarySoldier("士兵", 10000);
MilitarySoldier airman11 = new MilitarySoldier("士兵", 10000);
MilitarySoldier airman12 = new MilitarySoldier("士兵", 10000);
captain4.add(airman10);
captain4.add(airman11);
captain4.add(airman12);
System.out.println("上将编制内的所有人员的薪水:" + CalcSalary.calcSalary(general));
System.out.println("上尉1编制内的所有人员的薪水:" + CalcSalary.calcSalary(colonel1));
System.out.println("上校2编制内的所有人员的薪水:" + CalcSalary.calcSalary(captain1));
}
}
要点:
1. 组合模式以不遵守单一责任原则换取透明性,让Client将组合和叶节点一视同仁。
2. 在实现组合模式时,有很多设计上的折衷。要根据需求平衡透明性和安全性。
3. 有时候系统需要遍历一个树枝构件的子构件很多次,这时候可以把遍历结果缓存起来。
4. 组合模式的实现中,可以让子对象持有父对象的引用进行反向追溯。
优点:
1. 组合模式可以很容易的增加新的构件。
2. 使用组合模式可以使客户端变的很容易设计,因为客户端可以对组合和叶节点一视同仁。
缺点:
1. 使用组合模式后,控制树枝构件的类型不太容易。
2. 用继承的方法来增加新的行为很困难。