设计模式可以帮助用户在更高层次上抽象细节更好地理解体系结构如果比较熟悉 GoF 设计模式和 JavaServer Faces (JSF) 框架本文可以帮助您洞察 JSF 框架中使用的设计模式深入理解其工作原理
本文探讨了 JSF 框架中使用的设计模式详细讨论的设计模式包括 SingletonModelViewControllerFactory MethodStateCompositeDecoratorStrategyTemplate Method 和 Observer 模式
设计模式和 JavaServer Faces (JSF) 技术
首先简要地介绍一下模式和 JSF 框架
模式设计模式是对问题和解决方案进行抽象的普遍适用的方法因为模式是所有开发人员和架构师公认的所以模式可以节约时间和资源用外行话来说模式就是关于某个人所共知的问题的经过验证的解决方案模式可以重用重用使得解决方案更健壮
Java Server Faces JSF 体系结构是一种 Web 应用程序框架它是 Java Community Process (JCP) 推动的有望成为 Web 应用程序开发的标准框架目前用于开发 Web 应用程序的框架有 多个这说明迫切需要实现框架的标准化这正是 JSF 框架的目标!
深入剖析 JSF 模式
现在我们来讨论 JSF 体系结构中的各种设计模式本文将详细讨论 SingletonModelViewControllerFactory MethodStateCompositeDecoratorStrategyTemplate Method 和 Observer 设计模式我将分析每种模式的用途及其在 JSF 框架中的作用
Singleton 模式
Singleton 模式的目的是保证类只有一个实例被加载该实例提供一个全局访问点当启动具有 JSF 支持的 Web 应用程序时Web 容器初始化一个 FacesServlet 实例在这个阶段FacesServlet 对每个 Web 应用程序实例化 Application 和 LifeCycle 实例一次这些实例就采用众所周知的 Singleton 模式通常只需要该类型的一个实例
使用 JSF 的 Web 应用程序只需要 Application 和 LifeCycle 类的一个实例LifeCycle 管理多个 JSF 请求的整个生命期因为其状态和行为在所有请求之间共享这些对象采用 Singleton 模式合情合理LifeCycle 维护的 PhaseListeners 也是 Singleton 模式的PhaseListeners 由所有 JSF 请求共享在 JSF 框架中可以广泛使用 Singleton 模式以减少内存占用和提供对象的全局访问NavigationHandler(用于确定请求的逻辑结果)和 ViewHandler(用于创建视图)也是使用 Singleton 模式的例子
ModelViewController (MVC)
MVC 模式的目的是从数据表示(View)中将数据(即 Model)分离出来如果应用程序有多种表示可以仅替换视图层而重用控制器和模型代码类似的如果需要改变模型可以在很大程度上不改变视图层控 制器处理用户动作用户动作可能造成模型改变和视图更新当用户请求一个 JSF 页面时请求发送到 FacesServletFacesServlet 是 JSF 使用的前端控制器 servlet和其他很多 Web 应用程序框架一样JSF 使用 MVS 模式消除视图和模型之间的耦合为了集中处理用户请求控制器 servlet 改变模型并将用户导航到视图
FacesServlet 是 JSF 框架中所有用户请求都要经过的控制器元素FacesServlet 分析用户请求使用托管 bean 对模型调用各种动作后台(backing)或托管(managed)bean 就是该模型的例子JSF 用户界面(UI)组件是视图层的例子MVC 模式把任务分解给具有不同技能的开发人员使这些任务能够同时进行这样 GUI 设计人员就可以使用丰富的 UI 组件创建 JSF 页面同时后端开发人员可以创建托管 bean 来编写专门的业务逻辑代码
Factory Method 模式
Factory Method 模式的目的是定义一个用于创建对象的接口但是把对象实例化推迟到子类中在 JSF 体系结构中Factory Method 模式被用于创建对象LifeCycleFactory 是一个创建和返回 LifeCycle 实例的工厂对象LifeCycleFactory 的 getLifeCycle (String LifeCycleId) 方法采用 Factory Method 模式根据 LifeCycleId 创建(如果需要)并返回 LifeCycle 实例自定义的 JSF 实现可以重新定义 getLifeCycle 抽象方法来创建自定义的 LifeCycle 实例默认的 JSF 实现提供默认的 LifeCycle 实例此外对于每个 JSF 请求FacesServlet 都从 FacesContextFactory 得到 FacesContextFacesContextFactory 是一个抽象类公开了 getFacesContext APIJSF 实现提供了 FacesContextFactory 和 getFacesContext API 的具体实现这是另外一个使用 Factory Method 模式的例子具体的 FacesContextFactory 实现创建 FacesContext 对象
State 模式
State 模式的目的是在表示状态的不同类之间分配与状态有关的逻辑FacesServlet 对 LifCycle 实例调用 execute 和 render 方法LifeCycle 协调不同的 Phrase 以便执行 JSF 请求在这里 JSF 实现就遵循了 State 模式如果没有使用这种模式LifeCycle 实现就会被大量的条件(即 if 语句)搅得一塌糊涂JSF 实现为每个状态(或阶段)创建单独的类并调用 stepphase 是一个抽象类定了每个 step 的公共接口在 JSF 框架中定义了六个 phrase(即 step)RestoreViewPhaseApplyRequestValuesProcessValidationsPhase UpdateModelValuesPhaseInvokeApplicationPhase 和 RenderResponsePhase
在 State 模式中LifeCycle 把 FacesContext 对象传递给 phase每个阶段或状态改变传递给它的上下文信息然后设置 FacesContext 本身中的标志表明下一个可能的步骤JSF 实现在每个步骤中改变其行为每个阶段都可以作为下一个阶段的起因FacesContext 有两种标志 renderResponse 和 responseComplete 可以改变执行的顺序每个步骤执行完成后LifeCycle 检查上一阶段是否设置了这些标志如果设置了 responseCompleteLifeCycle 则完全放弃请求的执行如果经过某个阶段后设置了 renderResponse 标志JSF 就会跳过剩下的阶段而直接进入 Render Response 阶段如果这两个标志都没有设置LifeCycle 就会按顺序继续执行下一步
Composite 模式
Composite 模式让客户代码能够统一处理复合对象和基本对象复合对象是基本对象的容器在第一阶段(Restore View 阶段)和最后一个阶段(Render Response 阶段)使用 JSF UI 组件构造 UI ViewUIComponentBase 就是 Composite 模式中 Component 抽象类的一个例子UIViewRoot 是 Composite 类而 UIOutput(比方说)就是叶子(或者基本类)UIComponentBase 类定义了叶子和复合对象的公共方法如编码/解码值和子节点管理函数子节点管理函数如 getChildren对于叶子节点返回空列表对于复合节点则返回其子节点
Decorator 模式
Decorator 模式的目的是不通过子类化动态扩展对象的行为JSF 框架有很多扩展点(即可插入机制)JSF 实现可使用 Decorator 模式替换默认的 PropertyResolverVariableResolverActionListenerNavigationHandler ViewHandler 或 StateManager通常自定义实现接受通过构造函数传递给它的默认实现的引用自定义实现仅仅改写功能的一个子集而将其他功能委托给默认实现 如果希望实现自定义的 ViewHandler改写默认 ViewHandler 实现的 calculateLocale 方法可以像 清单 那样编写 CustomViewHandler 类
清单 CustomViewHandler 片段
public class CustomViewHandler extends ViewHandler {
public CustomViewHandler(ViewHandler handler) {
super();
oldViewHandler = handler;
}
private ViewHandler oldViewHandler = null;
public void renderView (facesContext context UIViewRoot view) {
//delegate method to oldViewHandler
oldViewHandlerrenderView(context view);
}
//custom implementation of calculateLocale
public Locale calculateLocale(FacesContext context) {
}
}
Strategy 模式
Strategy 模式的目的是封装不同的概念JSF 框架采用 Strategy 模式使用委托实现模型呈现 UI 组件JSF 技术支持两种呈现模型在直接实现模型中UI 组件对收到的请求中的数据进行解码然后编码这些数据进行显示在委托实现模型中解码和编码操作委托给和组建关联的专门呈现器后一种模型利用了 Strategy 设计模式比直接实现更灵活在 Strategy 模式中将不同的算法封装在单独的对象中从而可以动态地改变算法JSF 实现可以用已有的 renderkit 实例注册另外的呈现器当应用程序启动的时候JSF 实现读取配置文件将这些呈现器和 UI 组件联系在一起
Template Method 模式
Template Method 模式的目的是将变化的步骤推迟到子类中而在父类中定义那些固定的算法步骤JSF 框架通过 PhraseListeners 展现了 Template Method 模式提供的功能采用 Template Method(或者 hook)使得 Web 作者可以为不同阶段之间的可选步骤提供实现而主要阶段仍然和 JSF 框架的定义一致JSF 框架提供了 PhaseListeners概念上类似于 Template Method 模式中的可变步骤JSF 框架有六个预定义的阶段在每个阶段之间Web 作者可以实现 PhaseListeners 来提供类似于 Template Method hook 的 hook事实上这种结构比 Template Method 模式更具有扩展性可以通过注册 PhraseId 为 ANY_PHRASE 的 PhaseListener 在每个阶段后提供 hook如果 PhaseId 是 ANY_PHASEJSF 实现就会在每个阶段之前和之后调用该 PhaseListenerJSF 框架中的实现略有不同因为可以根本没有 PhaseListener但是在 Template Method 模式中子类通常重新定义父类中抽象的可变步骤
Observer 模式
Observer 模式的目的是当目标对象的状态改变时自动通知所有依赖的对象(即观察器)JSF 在 UI 组件中实现了 Observer 模式JSF 有两类内建事件ActionEvent 和 ValueChangedEventActionEvent 用于确定用户界面组件(如按钮)的激活当用户单击按钮时JSF 实现通知添加到该按钮上的一个或多个动作监听程序于是该按钮被激活或者说按钮(主体)的状态改变了添加到按钮上的所有监听程序(即观察器)都收到通 知该主体状态已经改变类似的当输入 UI 组件中的值改变时JSF 实现通知 ValueChangeListener
结束语
JSF 框架利用了 SingletonModelViewControllerFactory MethodStateCompositeDecoratorStrategyTemplate Method 和 Observer 设计模式因为它的体系结构建立在已经验证的设计模式的基础上这是一个健壮的框架模式在 JSF 框架中得到了很好的利用