如果引用或轉貼,麻煩註明出處與本網誌連結,否則視為侵權。

2005年7月12日

J2EE Design Pattern : Application Controller筆記

J2EE Design Pattern : Application Controller筆記

正體中譯與整理 : Fred Wang (http://fredwang.blogspot.com)
內容來源 : "Core J2EE Design Pattern"

這個Pattern用來解決甚麼問題?
. 將Action與View的管理集中化與模組化

在展示層中在接收到需求後有兩件主要的工作 :
. 第一, 收到的需求由特定的Action來提供服務, 稱為Action Management
. 第二, 控制權轉交給適當的View, 稱為View Management

這些也可以集中在Front Controller處理, 但是當應用系統及程式複雜時,最好將這些行為移到不同的classes以提高程式的模組化,重用性及擴充性。

重點:
. 重用(reuse)action與view management的程式碼
. 提升需求控管的可擴充性, 例如逐漸將Use case的功能加到應用系統內。
. 提升程式碼的模組化及可維護性, 更容易擴充您的應用系統, 更容易測試你每一部份的需求控管程式, 而這些程式與Web Container是不相關的(與Web Contrainer相關的需求管控在Front Controller完成)。

解決方案 :
- 使用一個Application Controller集中需求處理元件(如Commands與Views)的擷取與呼叫
註 : 真正處理需求及展現結果的元件不是Application Controller, 而是Commands與Views, Application Controller可以視為根據需求找到對應處理的Command(或Action), 並分派給合適的View來處理要呈現的結果。

將這些程式碼從Front Controller分離的好處有 :
1. 從Front Controller中與特定網路協定相關的程式碼分離以提升程式模組化與重用性, 例如特定的application controller元件可以提供給許多的channels(如web application與web service)重複使用來控管需求。這些控管有資料驗證(Validation), error handling, authentication, 存取控制(access control)等。
2. 與Servlet-based Front Controller分離以便於在Web container外進行測試
註 : Application Controller內部會有與Servlet及Web Container有關的API呼叫, 因此, 程式設計師進行這部份功能的單元測試就不一定要與未來執行環境相同(不需用相同的Web Container)

Pattern內的成員及責任
. Client(需求端) : 負責呼叫Application Controller, 通常維Front Controller或Intercepting Filter

. Application Controller : 使用Mapper解決收到的需求及對應的Action及View之間委派(Delegate)或分派(Dispatch)
註 : Delegate與Dispatch不同, Delegate只是將部分工作委派特定對象處理, 但控制權還在本身, 但Dispatch則是將控制權交給分派的對象。

. Mapper : 使用Map來轉譯收到的需求為合適的action和view, 可視為工廠(factory)

. Map : 放置目標資源的參考關係, 可能是Class或registry。
註 : 直接控管方式是直接可從Map中取出參考關係, 而間接控管方式是Map內包含物件, 須透過此物件才可找到目標資源。

以Jakarta Struts為例, Command Factory將request與action對應的關係從struts-config.xml中找出來, 傳回Command Map(ActionMapping)物件。這裡的Command Factory就是Mapper, ActionMappig就是Map。




參考 : http://www.corej2eepatterns.com/Patterns2ndEd/ApplicationController.htm

2005年7月11日

J2EE Design Pattern : Transfer Object筆記

J2EE Design Pattern : Transfer Object筆記

正體中譯與整理 : Fred Wang (http://fredwang.blogspot.com)
內容來源 : "Core J2EE Design Pattern"


這個Pattern用來解決甚麼問題?
跨層(presentation tier, business tier and integration tier)轉送多個資料元素, 並減少遠端呼叫造成網路的負擔。

J2EE應用系統用Session Facade 或Business Objects作為伺服器端商業元件並由其中的一些methods傳資料回需求端。這些商業元件常用如session beans與entity beans等遠端物件來實作。若這些商業元件採用較小的get及set methods,則需求端必需呼叫很多的getter methods才能取得所需的屬性內容值。

因為這些method的呼叫對enterprise bean而言都是遠端呼叫, 因此可能會造成效率上的問題。因為遠端呼叫會造成網路的負擔。即使需求端與EJB container在相同的JVM, OS或相同的實體機器上執行效能都會受影響。因此使用許多的遠端getter method的呼叫, 每次只傳回一點點資料, 這種方式非常沒有效率。

因此即使不是存取遠端元件,仍然需要存取封裝在不同層內的資料元件, 如商業層的Business Objects, 整合層的Data Access Objects, 仍需要以較大顆粒(傳遞物件)介面來傳送及與接收資料。

重點 :
. 需求端要存取其他層的元件來擷取或更新資料
. 要減少網路上遠端的需求次數。
. 要避免存取頻繁的應用系統造成高的網路流量使網路效能下降。

解決方案
- 使用Transfer Object來攜帶跨層間傳遞的多個資料元素。

Transfer Object用來讓跨層間的資料最佳化,Transfer Object將需求與回應間的傳送與接收的所有元素包含在單一個資料結構內。

Transfer Object以傳值的方式被傳送到需求端, 因此需求端對Transfer Object的所有呼叫, 是針對原始Transfer Object的副本,而非遠端的原始Transfer Object。

步驟 :
1. Component因需求來建立Transfer Object的instance並傳回給需求端
註 : Component可能是展示層的view helper, business delegate或command object; 或商業層的Business Object, Application Service或Service Facade等; 或整合層的Data Access Object。
2. 此時的Transfer Object為序列化的(serialized)並跨網路傳送到需求端, 需求端收到並使用這個Transfer Object的本地副本(local copy)
3. 需求端也可以產生自己的Transfer Object instance送到Component來執行資料更新。

實作上Transfer Object是一個Serializable plan old Java Object(POJO), 包含許多的members(attributes or fields), 且用單一的method call來完成所有資料的傳送。

實作策略 : (待續)

Class Diagram



參考 :
http://www.corej2eepatterns.com/Patterns2ndEd/TransferObject.htm

2005年7月9日

J2EE Design Pattern : Application Service筆記

J2EE Design Pattern : Application Service筆記

正體中譯與整理 : Fred Wang (http://fredwang.blogspot.com)
內容來源 : "Core J2EE Design Pattern"


這個Pattern用來解決甚麼問題?
要集中跨許多商業層元件與服務的商業邏輯提供簡單的介面給需求端。

Service Facade如Session Facade或POJO Facade內含很少甚至沒有商業邏輯,僅用來提供簡單的介面, 當應用系統實作的使用案例(use cases)由許多的商業物件(Business Objects)及商業服務(如Web Services)所完成, 不應該用商業物件來實作這個User Case內的商業物件與服務間的協調工作, 這將增加了商業物件間的耦合性(coupling)。

註 :
1. Session Facade及POJO(Plain Old Java Object) Facade都是一種Service Facade, Session Facade是一種提供遠端商業服務(如Web Services)的介面。POJO Facade提供的近端商業服務的介面, 這些近端商業服務為POJO, 如Business Object(另一種Design Pattern)
2. 簡單的說, Service Facade提供一個Use Case對外的單一服務介面。

重點 :
. 盡量減少Service Facade內的商業邏輯
. 商業邏輯包含在商業物件與服務內
. 在現有的商業層的元件與服務之上提供簡單的介面
. 將使用案例特定的邏輯(控制與協調邏輯)在商業物件外加以封裝

解決方案 :
- 使用一個Application Service集中與彙整商業處理,提供統一的服務層。

Application Service的七項功能 :
1. Application Service 提供一個集中的地方來實作商業邏輯, 這些商業邏輯內含商業物件及服務。也就是說用Application Service將高層次的商業邏輯封裝在一個元件, 而這個元件叫用一些商業物件與服務。

2. 即使你不使用商業物件, Application Service也可以提供集中的商業邏輯實作層。Application service 可以包含程序控制的商業邏輯, 這些商業邏輯用來實作不同的服務(要依序完成)及資料存取物件(Data Access Object)。

3. 在非EJB的應用系統, Application Service提供展示層與商業層物件(如商業物件或服務)間的中介功能以減少兩個層的耦合性(Coupling)。就介面的粗細緻的層次而言Application Service介於Service Facade與Business Object之間。

4. Application Service提供Service Facade基礎架構, 讓Service Facase變得更簡單, 包含更少的程式碼, 因為Service Facade只要將商業處理委派(Delegate)給Application Service就好了。 (Application Service包含商業邏輯而Session Facade不包含商業邏輯)

5. 以Session Facade為例, 當商業邏輯(高層次)變得複雜, 如果將這些邏輯放在特定的Session Facade內, 則這些邏輯將很難被其他的Session Facade叫用, 只能用copy and paste方式重用, 如此一來這些Session Facade將變的難以維護。Application Service就可用來放置這些可重用的邏輯,讓Session Facade變的簡單, 優雅且好維護。

6. Application Service 可用來處理應用系統間的互動, 不同Use Cases間的互動及不同需求端型態的互動。如Use Case特有的處理或特定需求端形態的處理。

7. Application Service也可以用來實作存取外部服務的邏輯, 如eMail system, legacy system或Web Service, 並提供可重用的服務元件。

實作這個Pattern的策略 : <準備中>



參考 : http://www.corej2eepatterns.com/Patterns2ndEd/ApplicationService.htm

2005年7月8日

J2EE Design Pattern : Service to Worker筆記

正體中譯與整理 : Fred Wang (http://fredwang.blogspot.com)
內容來源 : "Core J2EE Design Pattern"


這個Pattern用來解決甚麼問題?
在View顯示前要執行主要的需求控管(request handling)並執行商業邏輯處理。

檢視下面的問題,了解在View準備階段的需求處理過程有多少工作要完成:
. 控制邏輯有多複雜?
. 要傳回的內容有多少動態資料?
. 商業邏輯及資料模型有多複雜?

重點 :
. 一個需求透過指定的商業邏輯來取得用來產生回應的資訊(例如資料庫或檔案內的資訊)。
. View的選擇決定於商業服務(邏輯)產生的回應訊息(HTML, JSP等)。
. 可以使用Framework或library, 如Jakarta Struts, JSF等。

解決方案 :
- 用Service to Worker來集中控制與需求控管在控制權交給View前取得展示資料模型(Presentation Model 例如儲存在Session內的資料), View 就是基於這個展示模型來產生動態的回應。

註 : Service to Worker與Dispatcher View為兩個最常使用的方法。Service to Worker是以控制器(application controller)為中心的架構,Dispatcher View是以View為中心的架構, 它的商業處理是到View的處理時才被執行(例如在JSP中的scriptlet or tag library)

Service to Worker pattern 由許多的patterns所組成,包含Front Controller, Application Controller與 View Helper

步驟 :
1.Front Controller接收需求(request), 並處理與網路協定相關的元素(如HttpServletRequest..)然後產生Context Object, 交給Application Controller, 並委派Application Controller進行Action與View的管理。

2.Application Controller扮演Command Handler將request中的邏輯名稱(例如http://some.server.com/Controller?action=login中的"login")找到對應的Command(例如LoginCmd), 並呼叫(invoke)這個Command

3.特定Command用來呼叫特定的商業服務來產生展示資料模型。

4.然後Application Controller再將控制權轉交給特定的View

5.這個View透過View Helper將展示資料模型內的資料轉換成View所需的內容。這個View也可能是個合成的View(Composite View)

在此要注意的是, 商業邏輯在控制權轉交給View前就完成了, 而Dispatch View則在制權轉交給View之後才執行這些商業邏輯。

實作這個Pattern的策略 :
1. Front Controller有Servlet Front Strategy與JSP Front Controller兩種, 前者較好。(在Front Controller的筆記中介紹)
2. View Helper有Template-Based View Strategy, Controller-Based View Strategy, JavaBean Helper Strategy, Custom Tag Helper四種策略 (在View Helper的筆記中介紹)
3. Dispatcher in Controller Strategy : 就是將控制權轉交給View的派送程式放在Front Controller內, 這也是在Front Controller的筆記中介紹。



參考 : http://www.corej2eepatterns.com/Patterns2ndEd/ServiceToWorker.htm

2005年7月5日

透過Jakarta Beanutils將ResultSet轉成ArrayList

有關Jakarta Commons的Beanutils請見http://jakarta.apache.org/commons/beanutils

將ResultSet轉成ArrayList的範例程式 :
import java.sql.*;
import java.util.*;
import org.apache.commons.beanutils.*;

public class DynaBeanArrayList {
public DynaBeanArrayList() {
}
public ArrayList getArrayList(ResultSet rs) throws Exception{
ArrayList results = new ArrayList(); // To hold copied list
try{
ResultSetDynaClass rsdc = new ResultSetDynaClass(rs);
BasicDynaClass bdc = new BasicDynaClass("DynaBeanTemplate", BasicDynaBean.class, rsdc.getDynaProperties());
Iterator rows = rsdc.iterator();
while (rows.hasNext()) {
DynaBean oldRow = (DynaBean) rows.next();
DynaBean newRow = bdc.newInstance();
PropertyUtils.copyProperties(newRow, oldRow);
results.add(newRow);
}
return results;
}
catch(Exception e){
return null;
}
}
}