不知道是何种原因,但可能是某些地方理解错了,这门课和高级数据库是我研究生阶段最差的课,也是至今为止不是A级的课。
把我期末做的report贴上来,也算是一种纪念吧。
JSF 框架中的设计模式分析
JSF(JavaServer(TM) Faces)是一种简化Java服务器上的应用的用户交互界面的建造的技术。拥有不同技能的开发者都可以在一个页面中通过组装可重用的UI组件,将这些组件连接到应用数据源,配置有客户向服务器端的事件处理器的事件来快速得建立起web应用。(http://javaserverfaces.java.net/)。
本篇文章参见了IBM developer上,发表于2006年的对于JSF框架分析的指引(http://www.ibm.com/developerworks/cn/java/wa-dsgnpatjsf.html),并结合下载最新的JSF源代码(version 2.1.4,http://javaserverfaces.java.net/download.html), JSF中得设计模式进行了更详尽的分析和扩展。
由于有些设计模式和现有的源代码有出入,对设计模式的示例做出了相应的调整。本文中的实例代码均出自于JSF2.1.4的源代码,但为了能够更清晰的体现设计模式,对源代码做了大量的删节,特此提醒。
但是由于本人的能力有限以及报告作业的时间限制,文中可能会出现错误,请读者见谅。另外由于本文附上了源代码,篇幅较长,所以其编排采用了word标准的大纲格式,可以使用导航面板按小标题轻松浏览。
仅以此文向设计模式课程致敬!
1. Singleton 模式
意图
保证类只有一个实例,并提供一个访问它的全局访问点。
使用性:
当类是有一个实例而且客户可以从一个众所所周知的访问点访问它时。
当这个唯一实例应该是通过子类化可扩展的,而且客户应该无需更改代码就能使用一个扩展的实例时
结构:
JSF 实例
参与者:
com.sun.faces.config
结构:

实现:
packagecom.sun.faces.config;
publicclass WebConfiguration {
private ServletContext servletContext;
private WebConfiguration(ServletContextservletContext) {
this.servletContext = servletContext;
String contextName =getServletContextName();
initSetList(servletContext);
processBooleanParameters(servletContext, contextName);
processInitParameters(servletContext,contextName);
if (canProcessJndiEntries()) {
processJndiEntries(contextName);
}
cachedListParams = newHashMap<WebContextInitParameter, String []>(3);
getOptionValue(WebContextInitParameter.ResourceExcludes, " ");
getOptionValue(WebContextInitParameter.DefaultSuffix, " ");
getOptionValue(WebContextInitParameter.FaceletsViewMappings,";");
}
public static WebConfigurationgetInstance(ServletContext servletContext) {
WebConfiguration webConfig =(WebConfiguration)
servletContext.getAttribute(WEB_CONFIG_KEY);
if (webConfig == null) {
webConfig = newWebConfiguration(servletContext);
servletContext.setAttribute(WEB_CONFIG_KEY, webConfig);
}
return webConfig;
}
}
分析:
一般配置文件都是唯一的,被设计成单例是很常见的做法。WebConfiguration类虽然不是标准的单例模式的实现,但是体现了非常明显的单例模式的意图。因为:1.WebConfiguration的构造器被设置成private以避免其他程序实例化它,获取默认的WebConfigurate需要通过getInstance()函数。
2. Factory Method 模式
意图:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到子类。
适用性:
当一个类不知道它所必须创建的对象的类的时候。
当一个类希望由它的子类来指定它所创建的对象的时候。
当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮组子类是代理者这一信息局部化的时候。
结构:

JSF实例:
参与者:
javax.faces.lifecycle.LifecycleFactory
com.sun.faces.lifecycle.LifecycleFactoryImpl
javax.faces.lifecycle.Lifecycle
com.sun.faces.lifecycle.LifecycleImpl
结构

实现:
packagejavax.faces.lifecycle;
public abstractclass LifecycleFactory implements FacesWrapper<LifecycleFactory> {
public LifecycleFactory getWrapped() {
return null;
}
public static final StringDEFAULT_LIFECYCLE = "DEFAULT";
public abstract void addLifecycle(StringlifecycleId,
Lifecyclelifecycle);
public abstract LifecyclegetLifecycle(String lifecycleId);
public abstract Iterator<String>getLifecycleIds();
}
package com.sun.faces.lifecycle;
public classLifecycleFactoryImpl extends LifecycleFactory {
public LifecycleFactoryImpl() {
super();
lifecycleMap = newConcurrentHashMap<String,Lifecycle>();
// We must have an implementation underthis key.
lifecycleMap.put(LifecycleFactory.DEFAULT_LIFECYCLE,
new LifecycleImpl());
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Created DefaultLifecycle");
}
}
public Lifecycle getLifecycle(StringlifecycleId) throws FacesException {
if (null == lifecycleId) {
throw new NullPointerException(
MessageUtils.getExceptionMessageString(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID,"lifecycleId"));
}
if (null ==lifecycleMap.get(lifecycleId)) {
Object[] params = {lifecycleId};
String message =
MessageUtils.getExceptionMessageString(
MessageUtils.CANT_CREATE_LIFECYCLE_ERROR_MESSAGE_ID,
params);
throw newIllegalArgumentException(message);
}
Lifecycle result =lifecycleMap.get(lifecycleId);
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("getLifecycle:" + lifecycleId + " " + result);
}
return result;
}
}
public abstractclass Lifecycle {
public abstract voidaddPhaseListener(PhaseListener listener);
public abstract void execute(FacesContextcontext) throws FacesException;
public abstract PhaseListener[]getPhaseListeners();
public abstract voidremovePhaseListener(PhaseListener listener);
public abstract void render(FacesContextcontext) throws FacesException;
}
public classLifecycleImpl extends Lifecycle {
private Phase response = newRenderResponsePhase();
private Phase[] phases = {
null, // ANY_PHASE placeholder, not areal Phase
new RestoreViewPhase(),
new ApplyRequestValuesPhase(),
new ProcessValidationsPhase(),
new UpdateModelValuesPhase(),
new InvokeApplicationPhase(),
response
};
private List<PhaseListener> listeners=
newCopyOnWriteArrayList<PhaseListener>();
/*…….*/
}
分析:
FactoryMethod模式主要是通过工厂来创建需要的产品,而不是自己来创建。一般寻找框架中设计模式,如果使用了工厂模式,一般会在命名中加入Factory。在使用LifecycleFactory创建Lifecycle时,使用接口,分别对应Creator和Product。真正的实现放在LifecycleFactoryImpl和LifecycleImpl中实现,分别对应ConcreteCreator和ConcreteProduct。而且工厂模式在返回工厂制造的产品时,有明显的表征函数getProduct()来返回工厂制造的产品,在实例源代码中为getLifecycle()函数。
3. State 模式
意图:
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
适用性:
一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立地类中。这使得你可以依据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立发生变化。
结构
JSF实例
参与者:
com.sun.faces.lifecycle.LifecycleImpl
com.sun.faces.lifecycle.Phase
com.sun.faces.lifecycle.ApplyRequestValuesPhase
com.sun.faces.lifecycle.InvokeApplicationPhase
com.sun.faces.lifecycle.ProcessValidationsPhase
com.sun.faces.lifecycle.RenderResponsePhase
com.sun.faces.lifecycle.RestoreViewPhase
com.sun.faces.lifecycle.UpdateModelValuesPhase
结构:

实现:
packagecom.sun.faces.lifecycle;
public classLifecycleImpl extends Lifecycle {
private Phase[] phases = {
null, // ANY_PHASE placeholder, not areal Phase
new RestoreViewPhase(),
new ApplyRequestValuesPhase(),
new ProcessValidationsPhase(),
new UpdateModelValuesPhase(),
new InvokeApplicationPhase(),
response
};
public void execute(FacesContext context)throws FacesException {
if (context == null) {
throw new NullPointerException
(MessageUtils.getExceptionMessageString
(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID,"context"));
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("execute(" +context + ")");
}
for (int i = 1, len = phases.length -1; i < len; i++) { // Skip ANY_PHASE placeholder
if (context.getRenderResponse() ||
context.getResponseComplete()){
break;
}
phases[i].doPhase(context, this,listeners.listIterator());
}
}
}
package com.sun.faces.lifecycle;
public abstractclass Phase {
public void doPhase(FacesContext context,
Lifecycle lifecycle,
ListIterator<PhaseListener> listeners) {
context.setCurrentPhaseId(getId());
PhaseEvent event = null;
if (listeners.hasNext()) {
event = new PhaseEvent(context,this.getId(), lifecycle);
}
Timer timer = Timer.getInstance();
if (timer != null) {
timer.startTiming();
}
try {
handleBeforePhase(context,listeners, event);
if (!shouldSkip(context)) {
execute(context);
}
} catch (Throwable e) {
queueException(context, e);
} finally {
try {
handleAfterPhase(context,listeners, event);
} catch (Throwable e) {
queueException(context, e);
}
// stop timing
if (timer != null) {
timer.stopTiming();
timer.logResult(
"Execution time forphase (including any PhaseListeners) -> "
+this.getId().toString());
}
context.getExceptionHandler().handle();
}
}
public abstract void execute(FacesContextcontext) throws FacesException;
}
packagecom.sun.faces.lifecycle;
public classApplyRequestValuesPhase extends Phase {
public void execute(FacesContextfacesContext) throws FacesException {
UIComponent component =facesContext.getViewRoot();
assert (null != component);
try {
component.processDecodes(facesContext);
} catch (RuntimeException re) {
String exceptionMessage =re.getMessage();
}
}
}
*Note: 其他的几个phase的实现InvokeApplicationPhase,ProcessValidationsPhase,RenderResponsePhase,RestoreViewPhase,UpdateModelValuesPhase雷同,不在此重复贴代码
分析:
State模式的主要特征就是对象的行为和状态相关,对象在切换状态时,通过切换状态变量运行时的类型来实现,因此代表Context的对象LifeCycleImpl负责切换State,而代表State的对象接口的Phase描述State在状态下应该实现的行为,几个State的实现类来显现状态行为方法,在此为execute()。识别state的类和上下文的切换类是识别该模式的重点。
4. Composite 模式
意图:
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
适用性:
你想表示对象的部分-整体层次结构
你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中得所有对象。
结构:

JSF实例
参与者:
javax.faces.component.UIComponentBase;
javax.faces.component.UIComponent
结构:

实现:
packagejavax.faces.component;
public abstractclass UIComponentBase extends UIComponent {
public void add(int index,UIComponent element) {
if (element == null){
thrownew NullPointerException();
} else if ((index< 0) || (index > size())) {
thrownew IndexOutOfBoundsException();
} else {
eraseParent(element);
super.add(index,element);
element.setParent(component);
}
}
public UIComponent remove(intindex) {
UIComponent child =get(index);
super.remove(index);
child.setParent(null);
return (child);
}
public List<UIComponent>getChildren() {
if (children ==null) {
children= new ChildrenList(this);
}
return (children);
}
public voidprocessUpdates(FacesContext context) {
if (context == null){
thrownew NullPointerException();
}
if (!isRendered()) {
return;
}
pushComponentToEL(context,null);
Iterator kids =getFacetsAndChildren();
while(kids.hasNext()) {
UIComponentkid = (UIComponent) kids.next();
kid.processUpdates(context);
}
popComponentFromEL(context);
}
public UIComponent getParent() {
return (this.parent);
}
}
packagejavax.faces.component;
public abstractclass UIComponent implements PartialStateHolder, TransientStateHolder,SystemEventListenerHolder,
ComponentSystemEventListener {
public abstract UIComponent getParent();
public abstract List<UIComponent>getChildren();
public abstract voidprocessUpdates(FacesContext context);
}
分析:
Composite模式常用于界面组件的管理,将一个UI组件作为复合对象进行处理。在JSF中UIComponentBase可以管理一组UIComponent,本身UIComponentBase又是UIComponent接口的一组实现。在生成实例时,可以递归调用,在内存中生成一颗对象树,从而形成整个UI界面的组件。寻找Composite模式时,父类和子类继承于同一个类,且子类中的成员列表都为父类的类型,这是Composite模式的重要特征。
5. Decorator 模式
意图:
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式比相比生成子类更为灵活。
适用性:
在不影响其他对象的情况下,以动态、透明的方式给单给对象添加职责。
处理那些可以撤销的职责。
当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立地扩展,为支持每一种组合将产生大量的子类,使得子类数据呈爆炸性增长。另一种情况可能是因为定义被隐藏,或类定义不能用于生成子类。
结构:

JSF实例
参与者:
javax.faces.el.PropertyResolver
javax.faces.el.PropertyResolverImpl
结构:

实现:
packagejavax.faces.el;
public abstractclass PropertyResolver {
public abstract Object getValue(Objectbase, int index)
throws EvaluationException,PropertyNotFoundException;
}
packagecom.sun.faces.el;
public classPropertyResolverImpl extends PropertyResolver {
private PropertyResolver delegate;
public Object getValue(Object base, intindex) {
if (base == null) {
return null;
}
if (delegate != null) {
return delegate.getValue(base,index);
}
if (base.getClass().isArray()) {
try {
return Array.get(base, index);
} catch(ArrayIndexOutOfBoundsException aioobe) {
return null;
}
} else if (base instanceof List) {
try {
return ((List) base).get(index);
} catch (IndexOutOfBoundsExceptionioobe) {
return null;
}
} else {
throw newPropertyNotFoundException(MessageUtils.getExceptionMessageString(
MessageUtils.EL_PROPERTY_TYPE_ERROR_ID,
base));
}
}
}
分析:
Decorator模式的特征被修饰者和修饰者继承自同一类,在Decorator中有一个指针指向被修饰着。在PropertyResolverImpl中存储了类型为PropertyResolver 的delegate变量,指向它所修饰的继承自PropertyResolver的对象实例。这是识别Decorator模式的特征。
小结
在框架源代码中识别设计模式,并把它映射成GoF设计模式一书所描述的经典的设计模式,并不是一件容易的事,即便是在有指引的情况下。
其原因是:
一、开源框架的源代码的数量庞大,要找到对应的模式需要相应的技巧,
二、本文参见的指引并没有将设计模式映射到类图和源代码,本文做了这项工作,这个映射过程是枯燥而繁琐的。
三、开源框架对于设计模式的实践并非是严格按照GoF设计模式的描述的,在实际操作过程中会有一定的变异,从而使得在源代码中寻找的的设计模式的类图抽象和GoF设计模式一书中得描述有出入。
四、在提炼描述设计模式的时候,需要对源代码进行大量的删减,以尽可能一最简单的方式变现源代码中体现的设计模式。
在这个过程中对于设计模式又有了更深的层次,而且对于开源框架的掌握也不在局限于api层面,有一个更高抽象层次上的理解,也无愧于设计模式的课程学习了。于此同时,其实也不难认识到设计模式是一个不断实践精炼的过程,要在未来的开发道路上,更好地使用设计模式,需要进一步的体会和实践。