命令模式在MVC框架中的應用

命令模式:

定義:把一個請求或者操作封裝在命令對象中。命令模式允許系統使用不同的請求把客戶端參數化,對請求排隊或者記錄請求日誌,可以提供命令的撤銷和恢復功能。

7d8e0742-c5d2-30aa-9e98-2922efcbc1fb

Invoker類 被客戶端調用,可以接受命令請求,設計命令隊列,決定是否相應該請求,記錄或撤銷或重做命令請求,記錄日誌等等.

  1.  

Command類,將一個請求封裝成一個對象,將一個請求具體化,方便對請求記錄。

  1.  

ConcreteCommand類,可以將Receiver對象放到這個類裏面,這個類具體實現了要怎麼處理這個用戶的請求。

  1.  

Receiver類,其實這個類可以沒有,不過爲了讓設計看起來更整潔清楚。

  1.  

最後一個Client類。

  1.  

命令模式在MVC中的應用:

      Struts中,在模型層都要繼承一個Action接口,並實現execute方法,其實這個Action就是命令類。爲什麼Struts會應用命令模式,是因爲Struts的核心控制器ActionServlet只有一個,相當於Invoker,而模型層的類會隨着不同的應用有不同的模型類,相當於具體的Command。這樣,就需要在ActionServlet和模型層之間解耦,而命令模式正好解決這個問題。

      MVC Model2 實現的Web框架示意圖:

image002

說明:

  • 視圖層採用JSP實現
  • 控制器採用Servlet實現,整個框架採用同一個Servlet,以實現請求的中轉
  • 模型層採用Java實現,主要決定用來做什麼
  • 在模型層後添加了一個DAO,目的是將決定做什麼和具體怎麼做分開

      整個Web框架大致的流程是:首先客戶端發送請求,提交JSP頁面給中轉器(Servlet);中轉器根據客戶的請求,選擇相應的模型層,即Logic,Logic進行相應的邏輯處理;如果需要使用數據庫,則通過DAO進行相應的數據庫操作。

下面主要看一下控制層和模型層的設計,應用命令模式:

1.控制層設計

      控制層主要用來轉發從視圖層傳來的數據和請求到相對應的模型層,因此,實現它最好的方式莫過於使用Servlet了。當從視圖層獲取請求後,首先通過對web.xml文件的配置,使其轉入Servlet,在Servlet中完成對頁面中數據的封裝和對相應模型的選擇,然後再到相應的模型層進行數據處理;當在模型層數據處理完畢後,通過RequestDispatcher將處理後的數據返回相應的視圖頁面。

      在Servlet中,將使用doPost()來處理相應的中轉請求,如果開發人員使用get提交方式,則使用如下方式進行處理。示例代碼如下:

 

代碼說明:

  • 不論採用get還是post提交方式,都將執行do_Dispatcher(req, res)方法。
  • do_Dispatcher(req, res)是用來處理視圖層發送來的請求的方法。

      如果直接使用request方式來獲取從頁面提交的數據,在要獲取的數據比較多的情況下,會比較煩瑣,而且直接將request傳遞給模型層不符合Model 2規範。所以,這裏將對從頁面傳來的值進行封裝,將其放在一個Map中,然後再傳遞給模型層,這樣在模型層就可以直接使用Map中的值。示例代碼如下:

 

代碼說明:

  • req.setCharacterEncoding("GBK"),這裏首先將從視圖層傳來的數據設定編碼爲GBK。
  • HashMap infoIn = new HashMap(),定義一個HashMap,用來存放從request中獲取的數據。
  • req.getParameterNames(),用來獲取從頁面中傳來的所有元素。
  • req.getParameterValues(),用來根據元素名稱來獲取元素對應的值,並將元素名稱和值的對應關係存入HashMap中。如果元素的值爲空,則在HashMap中將元素名稱對應的值置爲空;如果只有一個值,則將該值存入;如果有多個值,則存入數組。

命令模式使用:

一個視圖對應一個模型,也可能一個視圖對應多個模型,但只有一個控制器,所以,爲了實現一個控制器可以轉發到多個模型中去,就需要使用接口,讓所有模型都實現這個接口,然後在控制器裏,僅僅是面對接口編程即可。這裏定義一個接口Action.java,Action.java的示例代碼如下:

 

在控制器中只針對這個接口處理即可。示例代碼如下:

 

代碼說明:

  • getActionName()方法是獲取實現接口Action的類的名稱和所在的包。示例代碼如下:

 

使用RequestDispatcher返回視圖層。示例代碼如下:

 

代碼說明:

  • 這裏表示JSP文件放在項目中系統名下的jsp文件夾下。

2.模型層設計

假定有一個模型層類爲WebExamAction.java,主要用來負責在線考試系統的業務處理,則這個類要實現Action接口。示例代碼如下:

 

代碼說明:

  • 這裏,在doAction中根據從頁面傳來的action進行動作請求的轉換。
  • 通過一個名爲infoIn的HashMap,來負責傳入頁面中元素的值。
  • 通過一個名爲infoOut的HashMap,來負責將處理後的數據傳出。

可以看出,如果模型層都實現接口Action,實現doAction方法,即可實現動作請求的轉換。

命令模式要點:

1.Command模式的根本目的在於將“行爲請求者”與“行爲實現者”解耦,在面嚮對象語言中,常見的實現手段是“將行爲抽象爲對象”。
2.實現Command接口的具體命令對象ConcreteCommand有時候根據需要可能會保存一些額外的狀態信息。
3.通過使用Compmosite模式,可以將多個命令封裝爲一個“複合命令”MacroCommand。
4.Command模式與C#中的Delegate有些類似。但兩者定義行爲接口的規範有所區別:Command以面向對象中的“接口-實現”來定義行爲接口規範,更嚴格,更符合抽象原則;Delegate以函數簽名來定義行爲接口規範,更靈活,但抽象能力比較弱。
5.使用命令模式會導致某些系統有過多的具體命令類。某些系統可能需要幾十個,幾百個甚至幾千個具體命令類,這會使命令模式在這樣的系統裏變得不實際。

適用性:

    在下面的情況下應當考慮使用命令模式:
1.使用命令模式作爲"CallBack"在面向對象系統中的替代。"CallBack"講的便是先將一個函數登記上,然後在以後調用此函數。
2.需要在不同的時間指定請求、將請求排隊。一個命令對象和原先的請求發出者可以有不同的生命期。換言之,原先的請求發出者可能已經不在了,而命令對象本身仍然是活動的。這時命令的接收者可以是在本地,也可以在網絡的另外一個地址。命令對象可以在串形化之後傳送到另外一臺機器上去。
3.系統需要支持命令的撤消(undo)。命令對象可以把狀態存儲起來,等到客戶端需要撤銷命令所產生的效果時,可以調用undo()方法,把命令所產生的效果撤銷掉。命令對象還可以提供redo()方法,以供客戶端在需要時,再重新實施命令效果。
4.如果一個系統要將系統中所有的數據更新到日誌裏,以便在系統崩潰時,可以根據日誌裏讀回所有的數據更新命令,重新調用Execute()方法一條一條執行這些命令,從而恢復系統在崩潰前所做的數據更新。

參考:

1.《自己動手寫Struts:構建基於MVC的Web開發框架》

2.《敏捷軟件開發:原則、模式與實踐》

3.《Head First設計模式》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章