設計模式提供通用問題的經驗解決方案,JSF 作為 Java EE 標準 Web 框架,其架構大量運用 GoF 設計模式。理解這些模式有助於深入掌握 JSF 運作原理、擴充點與最佳實踐。
| 模式 | JSF 應用場景 | 關鍵類別/介面 | 效益 |
|---|---|---|---|
| Singleton | 每個 Web 應用僅需一個實例 | Application、Lifecycle、NavigationHandler、ViewHandler、PhaseListener | 減少記憶體佔用、提供全域存取點、狀態共享 |
| MVC (Model-View-Controller) | 關注點分離:模型、視圖、控制器 | FacesServlet (Controller)、Managed Bean (Model)、UIComponent (View) | 前端設計師與後端開發並行、可替換視圖技術、業務邏輯重用 |
| Factory Method | 延遲實例化至具體實作 | LifecycleFactory.getLifecycle()、FacesContextFactory.getFacesContext() | 支援自訂 Lifecycle/Context 實作、解耦框架與應用 |
| State | 請求處理生命週期的六個階段 | Lifecycle、Phase (RestoreView、ApplyRequestValues、ProcessValidations、UpdateModelValues、InvokeApplication、RenderResponse) | 避免大量條件判斷、每階段封裝獨特行為、動態控制流程跳轉 |
| Composite | UI 元件樹結構 | UIComponentBase (Component)、UIViewRoot (Composite)、UIOutput (Leaf) | 統一處理單一元件與容器元件、遞迴編碼/解碼、子元件管理 |
| Decorator | 擴充預設實作而不繼承 | PropertyResolver、VariableResolver、ActionListener、NavigationHandler、ViewHandler、StateManager | 僅覆寫需變更功能、其餘委派給預設實作、多重裝飾疊加 |
| Strategy | 渲染器可換裝機制 | RenderKit、Renderer、ResponseWriter | 同一 UIComponent 可輸出 HTML/WML/VoiceXML、運行時切換渲染策略 |
| Template Method | 階段間擴充點 | PhaseListener (beforePhase/afterPhase)、ANY_PHASE | 框架定義骨架、應用填充可變步驟、比傳統 Template Method 更靈活 |
| Observer | UI 事件通知機制 | ActionEvent/ActionListener、ValueChangeEvent/ValueChangeListener | 鬆耦合事件源與處理器、支援多監聽器、標準化事件傳播 |
Lifecycle.execute() 與 render() 依序執行六個 Phase。每個 Phase 修改 FacesContext 並設定旗標:
responseComplete:終止後續處理,直接結束請求renderResponse:跳過中間階段,直接進入 Render Response這種設計讓驗證失敗、導航攔截等邏輯極其清晰。
public class CustomViewHandler extends ViewHandler {
private ViewHandler wrapped;
public CustomViewHandler(ViewHandler wrapped) {
this.wrapped = wrapped;
}
@Override
public Locale calculateLocale(FacesContext context) {
// 自訂語系判斷邏輯
return determineUserLocale(context);
}
@Override
public void renderView(FacesContext context, UIViewRoot view) {
wrapped.renderView(context, view); // 委派其餘功能
}
// 其他方法同理委派...
}
在 faces-config.xml 註冊:
<application>
<view-handler>com.example.CustomViewHandler</view-handler>
</application>
後者支援多種裝置輸出(HTML、WAP、Voice),運行時可切換 RenderKit。
<h:commandButton value="送出" action="#{bean.save}">
<f:actionListener type="com.example.AuditListener"/>
<f:actionListener binding="#{bean.customListener}"/>
</h:commandButton>
點擊按鈕 → 產生 ActionEvent → 通知所有註冊 ActionListener → 執行 Action 方法 → 導航處理。
JSF 建立在經驗證的設計模式之上,形成健壯、可擴充的架構。掌握這九大模式,不僅能更有效使用 JSF,更能在需要客製化時精準切入擴充點,避免破壞框架內部協作機制。