http://blog.csdn.net/significantfrank/article/details/7712053
1. Command Pattern
基本定義: 把Command(Request)封裝成對象,把發出命令(Invoker)的責任和執行命令(Receiver)的責任分割開,委派給不同的對象。
責任划分有什么好處?
責任約單一,內聚性越高,可重用的可能性越大,試想下,如果服務員不僅要點菜,還要去做菜,會是什么情景。
為什么把Invoker和Receiver解耦好處多?
類之間的耦合越低,可擴展的可能性越高。解耦后,更換一個服務員並不會影響廚師的工作
那么把Request封裝成對象具體是什么意思呢?
在遙控器Remote Control例子中,比如我有一個‘開燈’的Request,那么就應該對應有一個LightOnCommand對象,關燈就應該有LightOffCommand
在Web應用中,我有一個add user的Request,那么就應有一個AddUserCommand去處理請求, 或者用struts的name convention就是AddUserAction.
那么在Struts中又是怎么運用Command Pattern的呢?
Client : FilterDispatcher Servlet
Invoker: ActionInvocation
Command: Action (not a must in Struts2)
ConcreteCommand:AddUserAction
Receiver: ServiceImpl (not a must, depends how many logic you want to put into concreteCommand)
Struts,你什么時候調用的setCommand()?
用戶定義了Action Mapping在struts.xml里,在web container啟動時,ConfigurationManager 就裝載了struts.xml,當Request過來時,Struts Framework會根據當前的URL去找ConfigurationManager所對應的concreteCommand/Action, 然后這個Action會被set到ActionInvocation
Command Interface是必須的嗎?
在struts1中,有一個Interface,所有的Action都必須是它的實現。但是在Struts2中,Action可以是任意的POJO,因為在Runtime的時候,具體的Action是什么,該調用它的什么方法,都可以通過配置文件(MetaData)+ Java Reflection來實現。這種新方式的好處是POJO Action沒有了對框架的依賴,測試將會更加容易。缺點是因為沒有interface的約束,調用Action的什么方法完全取決於默認值(比如execute)或是配置文件中的配置。若設置不妥,只有在Runtime的時候才能發現錯誤。
Receiver 是必須得嗎?
不是,取決於你Action的厚度,如果你想讓Action很輕的話,那么通常你會在Action中使用UserService.addUser()去做事情,此時的UserService就是Receiver。把Action設計的厚點,直接把addUser的logic放在Action中也是可以的。
Struts2中運用了command的思想,但並沒有嚴格的按照其經典模型實現,而是做了些變通,這些變通乍看起來可能是有點違背設計原則,比如說取消了Action Interface,這不是反模式嗎,反面向接口的編程嗎,但仔細想想,這里我們真的需要這個接口嗎?通過配置文件+Reflection,我們同樣可以做到在Runtime的時候給ActionInvocation注入不同的Action的目的。而接口卻增加了用戶實現對框架的依賴,降低了程序的可測性,所以這樣的變通其實是有積極意義的,雖然我們損失了一點點接口作為契約所帶來的好處。
2. Interceptor Pattern
於其說這是模式,不如說這是AOP和Pipeline思想的結合,只不過Struts2中的實現非常的精巧,我不得不說這應該作為一個模式來推廣。
AOP : 所謂的AOP就是preProcess and postProcess, 系統應用中,許多地方是需要面向切面的,比如log,authentication,etc...。看過一些實現,如Java Dynamic,但不夠優雅。
Pipeline:分層就是把復雜的問題分層多個層次,每一層只處理問題的一小部分。通信的7層模型就是典型的范例
Interceptor Pattern 不僅為系統進行分層,而且還提供了AOP的處理,此外,還以一種plug-in的方式為用戶提供了無限擴展的可能。
應該怎么實現?
Interceptor的調用過程類似於一個棧式調用,所以想到遞歸是很自然的,這既避免了像Dynamic Proxy那樣的hack,又提供了更好的擴展性。
還是以Struts中的類作為例子,其類圖如下:
調用過程:
Pseudo 代碼:
ActionInvocation
- public Result invoke(){
- if( interceptors.hasNext() ){
- Interceptor interceptor = interceptors.next();
- result = interceptor.intercept(this);
- }
- else {
- action.execute();//如果沒有更多的Interceptor,停止遞歸,調用action
- }
- }
public Result invoke(){ if( interceptors.hasNext() ){ Interceptor interceptor = interceptors.next(); result = interceptor.intercept(this); } else { action.execute();//如果沒有更多的Interceptor,停止遞歸,調用action } }
InterceptorImpl
- public SomeInterceptor implements Interceptor{
- public Result intercept(ActionInvocation actionInvocation){
- //pre-processing
- // 遞歸調用
- result = actionInvocation.invoke();
- //post-processing
- return result;
- }
- }
public SomeInterceptor implements Interceptor{ public Result intercept(ActionInvocation actionInvocation){ //pre-processing // 遞歸調用 result = actionInvocation.invoke(); //post-processing return result; } }
More: http://www.cnblogs.com/west-link/archive/2011/06/22/2086591.html
http://bosy.dailydev.org/2007/04/interceptor-design-pattern.html
Struts2 架構圖
Struts 2 framework: http://viralpatel.net/blogs/introduction-to-struts-2-framework/