一 学习背景
在学习关于JSF组件时涉及到了composite模式,于是就查看一些资料,以下是自己对这种模式的理解。
二 自己的理解
1. composite模式意在组成任意复杂度的整体--部分组件层次结构,同时将单个组件或复合组件视为统一的接口。树形组织结构就是其中一种表现形式。
树形结构中有叶子结点和非叶子结点(根结点是特例),非叶子结点可以添加,删除(add(),delete())子结点,获取子结点(getChild()),叶子结点没有;此外树结构的所有节点还有共同的操作(operator())(论坛的帖子一般使用这种结构).
用户界面通常由两种基本类型的组件构造:基本组件和容器组件,容器组件可以在其内部嵌套任意数目的组件,而基本组件则不行。使用这两种组件类型,开发者可以建立更强大的组件,进而创建多姿多彩的用户界面。
但是在与复杂的组件层次结构打交道时,必须在容器组件和基本组件之间进行区分,比较麻烦,composite提供了一种解决方案。适用它的情况:
a. 要表现“部分-整体”的层次结构时
b. 希望在事件组件层次中,同等对待复合组件与单个组件。
2. 通过下面的示例来理解
示例1:
基类shape 类有两个派生类Circle和Square(相当于叶子结点或者是单个组件),第三个派生类CompositeShape是个组合体(相当于非叶子结点或者是容器组件),它持有一个含有多个shape实例的列表,当调用CompositeShape中的draw()时,它就把这个方法委托给列表中的每一个实例。
对于系统而言,一个CompositeShape实例就像是一个独立的shape,可以把它传给使用shape的方法或者对象。实际上,它只是一组shape实例的proxy.
程序:
Shape.java:

Public interface Shape ...{
Public void draw();
}
CompositeShape.java:
Public class CompositeShape implements Shape ...{
private Vector Comshape = new Vector();

public void add(Shape shape) ...{
Comshape.add(shape);
}

Public void draw() ...{
for( int i = 0; i < comshape.size(); i ++ ) ...{
Shape shape = (Shape) comshape.elementAt(i);
Shape.draw();
}
}
}
示例2:
抽象类Equipment就是Component定义,代表着组合体类的对象们,Equipment中定义几个共同的方法。
package com.interf;

public abstract class Equipment ...{
private String name;
private double netPrice;
private double discountPrice;

public Equipment(final String name) ...{
this.name = 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 boolean remove(Equipment equipment) ...{ return false; }
//注意这里,这里就提供一种用于访问组合体类的部件方法。
public Iterator iter() ...{ return null; }}


Disk是组合体内的一个对象,或称一个部件,这个部件是个单独元素( Primitive)。
Disk.java:
package implEquip;
import com.interf.Equipment;

public class Disk extends Equipment ...{

public Disk(String name) ...{
super(name);
// TODO Auto-generated constructor stub
}
//定义Disk实价为1
public double netPrice() ...{
return 1.;
}
//定义了disk折扣价格是0.5 对折。
public double discountPrice() ...{
return .5;
}
}
CompsiteEquipment.java:
package implEquip;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import com.interf.Equipment;

public class CompositeEquipment extends Equipment ...{
private int i=0;
// 定义一个Vector 用来存放'儿子'
private List equipment = new ArrayList();

public CompositeEquipment(String name) ...{
super(name);
// TODO Auto-generated constructor stub
}


public boolean add(Equipment equipment) ...{
this.equipment.add(equipment);
return true;
}
public double netPrice() ...{
double netPrice=0.;
Iterator iter=equipment.iterator();
while(iter.hasNext())
netPrice+=((Equipment)iter.next()).netPrice();
return netPrice;
}

public double discountPrice() ...{
double discountPrice=0.;
Iterator iter=equipment.iterator();
while(iter.hasNext())
discountPrice+=((Equipment)iter.next()).discountPrice();
return discountPrice;
}
// 注意这里,这里就提供用于访问自己组合体内的部件方法。
// 上面dIsk 之所以没有,是因为Disk是个单独(Primitive)的元素.
public Iterator iter() ...{
return equipment.iterator() ;
}
// 重载Iterator方法
public boolean hasNext() ...{ return i<equipment.size(); }
// 重载Iterator方法
public Object next()...{
if(hasNext())
return equipment.get(i++);
else
throw new NoSuchElementException();
}
我们再看看CompositeEquipment的两个具体类:盘盒Chassis和箱子Cabinet,箱子里面可以放很多东西,如底板,电源盒,硬盘盒等;盘盒里面可以放一些小设备,如硬盘软驱等。无疑这两个都是属于组合体性质的。
Cabinet.java:
package implEquip;

public class Cabinet extends CompositeEquipment ...{
public Cabinet(String name) ...{
super(name);
// TODO Auto-generated constructor stub
} 
public double netPrice() ...{
return 1.+super.netPrice();
}
public double discountPrice() ...{
return .5+super.discountPrice();
}
}

Chassi.java:
package implEquip;

public class Chassis extends CompositeEquipment ...{

public Chassis(String name) ...{
super(name);
// TODO Auto-generated constructor stub
}
public double netPrice() ...{
return 1.+super.netPrice();
}
public double discountPrice() ...{
return .5+super.discountPrice();
}
}
至此我们完成了整个Composite模式的架构。我们可以看看客户端调用Composote代码:
CompositeTest.java:
package test;

import implEquip.Cabinet;
import implEquip.Chassis;
import implEquip.Disk;


public class CompositeTest ...{


/** *//**
* @param args
*/

public static void main(String[] args) ...{
// TODO Auto-generated method stub
Cabinet cabinet=new Cabinet("Tower");
Chassis chassis=new Chassis("PC Chassis");
// 将PC Chassis装到Tower中 (将盘盒装到箱子里)
cabinet.add(chassis);
// 将一个10GB的硬盘装到 PC Chassis (将硬盘装到盘盒里)
chassis.add(new Disk("10 GB"));

// 调用 netPrice()方法;
System.out.println("netPrice="+cabinet.netPrice());
System.out.println("discountPrice="+cabinet.discountPrice());

}

}
CompositeTest.java:
package test;
import implEquip.Cabinet;
import implEquip.Chassis;
import implEquip.Disk;

public class CompositeTest ...{

/** *//**
* @param args
*/
public static void main(String[] args) ...{
// TODO Auto-generated method stub
Cabinet cabinet=new Cabinet("Tower");
Chassis chassis=new Chassis("PC Chassis");
// 将PC Chassis装到Tower中 (将盘盒装到箱子里)
cabinet.add(chassis);
// 将一个10GB的硬盘装到 PC Chassis (将硬盘装到盘盒里)
chassis.add(new Disk("10 GB"));
// 调用 netPrice()方法;
System.out.println("netPrice="+cabinet.netPrice());
System.out.println("discountPrice="+cabinet.discountPrice());
}
}
上面调用的方法netPrice()或discountPrice(),实际上Composite使用Iterator遍历了整个树形结构,寻找同样包含这个方法的对象并实现调用执行.
控制台输出:
netPrice=3.0
discountPrice=1.5
三.Composite在JSF中的应用
JSF组件提供的实现非常接近Composite模式给出的一般性解决方案,不过(和Swing不同)这里的顶层和一般组件之间没有明显差异。
JSF提供了一个所有组件都要实现的UIComponent接口,UIComponentBase类为了方便组件开发者,定义了默认的行为。JSF有许多基本组件如UIForm和UIInput。另外可以创建自己的自定义组件。创建自定义组件时,必须要实现UIComponent接口或者继承UIComponentBase类
JSF为使用默认组件提供了方便的标记库。当页面被应用的用户提交时,FacesServlet 将根据这些标记所提供和搜集的信息实际建立一个组件树
第一层:form
第二层:label,outputtext,panel
第三层:cancel submit
在组件树中,根为UIViewRoot组件。在JSF的生命周期中,每调用当前组件树的process()方法,则此组件树内的每个子组件的process()方法都会被递归调用。例如:在应用请求值(Apply Request Values)阶段,JSF通过调用当前组件树中UIViewRoot组件的processDecodes()方法来达到更新,这个动作的结果是,每个子组件的processDecodes()方法都被调用;处理验证阶段(Process Validations),有processValidators();更新Model(Update Model values)时有processUpdates()方法;调用应用(Invoke Application)时,JSF调用UIViewRoot组件的processApplication()方法来启动此过程。
四.参考资料:
1 设计模式之Composite(组合) 板桥里人 http://www.jdon.com 2002/04/27
网址:http://www.jdon.com/designpatterns/composite.htm
2 《Mastering JavaServer Faces》中文版
3 《敏捷软件开发:原则、模式与实践》
4 《JSF实战》
本文详细介绍了组合模式的概念及其实现原理,并通过具体的示例代码解释了如何使用组合模式构建复杂的组件层次结构。此外,文章还探讨了组合模式在JavaServer Faces (JSF) 中的应用。
564

被折叠的 条评论
为什么被折叠?



