Composite定义:
将对象以树形结构组织起来以达成部分-整体 的层次结构使得客户端对单个对象和组合对象的使用具有一致性
Composite比较容易理解想到Composite就应该想到树形结构图组合体内这些对象都有共同接口当组合体一个对象的方法被调用执行时Composite将遍历(Iterator)整个树形结构寻找同样包含这个方法的对象并实现调用执行可以用牵一动百来形容
所以Composite模式使用到Iterator模式和Chain of Responsibility模式类似
Composite好处:
使客户端调用简单客户端可以一致的使用组合结构或其中单个对象用户就不必关系自己处理的是单个对象还是整个组合结构这就简化了客户端代码
更容易在组合体内加入对象部件 客户端不必因为加入了新的对象部件而更改代码
如何使用Composite?
首先定义一个接口或抽象类这是设计模式通用方式了其他设计模式对接口内部定义限制不多Composite却有个规定那就是要在接口内部定义一个用于访问和管理Composite组合体的对象们(或称部件Component)
下面的代码是以抽象类定义一般尽量用接口interface
public abstract class Equipment
{
private String name;
//实价
public abstract double netPrice();
//折扣价格
public abstract double discountPrice();
//增加部件方法
public boolean add(Equipment equipment) { return false; }
//删除部件方法
public boolean remove(Equipment equipment) { return false; }
//注意这里这里就提供一种用于访问组合体类的部件方法
public Iterator iter() { return null; }
public Equipment(final String name) { thisname=name; }
}
抽象类Equipment就是Component定义代表着组合体类的对象们Equipment中定义几个共同的方法
public class Disk extends Equipment
{
public Disk(String name) { super(name); }
//定义Disk实价为
public double netPrice() { return ; }
//定义了disk折扣价格是 对折
public double discountPrice() { return ; }
}
Disk是组合体内的一个对象或称一个部件这个部件是个单独元素( Primitive)
还有一种可能是一个部件也是一个组合体就是说这个部件下面还有儿子这是树形结构中通常的情况应该比较容易理解现在我们先要定义这个组合体
abstract class CompositeEquipment extends Equipment
{
private int i=;
//定义一个Vector 用来存放儿子
private Lsit equipment=new ArrayList();
public CompositeEquipment(String name) { super(name); }
public boolean add(Equipment equipment) {
thisequipmentadd(equipment);
return true;
}
public double netPrice()
{
double netPrice=;
Iterator iter=erator();
for(iterhasNext())
netPrice+=((Equipment)iternext()Price();
return netPrice;
}
public double discountPrice()
{
double discountPrice=;
Iterator iter=erator();
for(iterhasNext())
discountPrice+=((Equipment)iternext())discountPrice();
return discountPrice;
}
//注意这里这里就提供用于访问自己组合体内的部件方法
//上面dIsk 之所以没有是因为Disk是个单独(Primitive)的元素
public Iterator iter()
{
return erator()
{
//重载Iterator方法
public boolean hasNext() { return i<equipmentsize(); }
//重载Iterator方法
public Object next()
{
if(hasNext())
return equipmentelementAt(i++);
else
throw new NoSuchElementException();
}
}
上面CompositeEquipment继承了Equipment同时为自己里面的对象们提供了外部访问的方法重载了IteratorIterator是Java的Collection的一个接口是Iterator模式的实现
我们再看看CompositeEquipment的两个具体类:盘盒Chassis和箱子Cabinet箱子里面可以放很多东西如底板电源盒硬盘盒等盘盒里面可以放一些小设备如硬盘 软驱等无疑这两个都是属于组合体性质的
public class Chassis extends CompositeEquipment
{
public Chassis(String name) { super(name); }
public double netPrice() { return +Price(); }
public double discountPrice() { return +superdiscountPrice(); }
}
public class Cabinet extends CompositeEquipment
{
public Cabinet(String name) { super(name); }
public double netPrice() { return +Price(); }
public double discountPrice() { return +superdiscountPrice(); }
}
至此我们完成了整个Composite模式的架构
我们可以看看客户端调用Composote代码:
Cabinet cabinet=new Cabinet(Tower);
Chassis chassis=new Chassis(PC Chassis);
//将PC Chassis装到Tower中 (将盘盒装到箱子里)
cabinetadd(chassis);
//将一个GB的硬盘装到 PC Chassis (将硬盘装到盘盒里)
chassisadd(new Disk( GB));
//调用 netPrice()方法;
Systemoutprintln(netPrice=+Price());
Systemoutprintln(discountPrice=+cabinetdiscountPrice());
上面调用的方法netPrice()或discountPrice()实际上Composite使用Iterator遍历了整个树形结构寻找同样包含这个方法的对象并实现调用执行
Composite是个很巧妙体现智慧的模式在实际应用中如果碰到树形结构我们就可以尝试是否可以使用这个模式
以论坛为例一个版(forum)中有很多帖子(message)这些帖子有原始贴有对原始贴的回应贴是个典型的树形结构那么当然可以使用Composite模式那么我们进入Jive中看看是如何实现的
Jive解剖
在Jive中 ForumThread是ForumMessages的容器container(组合体)也就是说ForumThread类似我们上例中的 CompositeEquipment它和messages的关系如图
[thread]
| [message]
| [message]
| [message]
| [message]
| [message]
我们在ForumThread看到如下代码
public interface ForumThread {
public void addMessage(ForumMessage parentMessage ForumMessage newMessage)
throws UnauthorizedException;
public void deleteMessage(ForumMessage message)
throws UnauthorizedException;
public Iterator messages();
}
类似CompositeEquipment 提供用于访问自己组合体内的部件方法: 增加 删除 遍历