巷尾的酒吧

            BlogJava :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
            64 Posts :: 0 Stories :: 5 Comments :: 0 Trackbacks
          一、引言

           

          忙里偷閑,終于動(dòng)筆了。命令模式是從界面設(shè)計(jì)中提取出來的一種分離耦合,提高重用的方法。被認(rèn)為是最優(yōu)雅而且簡(jiǎn)單的模式,它的應(yīng)用范圍非常廣泛。讓我們一起來認(rèn)識(shí)下它吧。

           

          先從起源說起。在設(shè)計(jì)界面時(shí),大家可以注意到這樣的一種情況,同樣的菜單控件,在不同的應(yīng)用環(huán)境中的功能是完全不同的;而菜單選項(xiàng)的某個(gè)功能可能和鼠標(biāo)右鍵的某個(gè)功能完全一致。按照最差、最原始的設(shè)計(jì),這些不同功能的菜單、或者右鍵彈出菜單是要分開來實(shí)現(xiàn)的,你可以想象一下,word文檔上面的一排菜單要實(shí)現(xiàn)出多少個(gè)“形似神非”的菜單類來?這完全是行不通的。這時(shí),就要運(yùn)用分離變化與不變的因素,將菜單觸發(fā)的功能分離出來,而制作菜單的時(shí)候只是提供一個(gè)統(tǒng)一的觸發(fā)接口。這樣修改設(shè)計(jì)后,功能點(diǎn)可以被不同的菜單或者右鍵重用;而且菜單控件也可以去除變化因素,很大的提高了重用;而且分離了顯示邏輯和業(yè)務(wù)邏輯的耦合。這便是命令模式的雛形。

           

          下面我們將仔細(xì)的討論下命令模式。

           

           

          二、定義與結(jié)構(gòu)

           

          《設(shè)計(jì)模式》中命令模式的定義為:將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而使你可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化;對(duì)請(qǐng)求排隊(duì)或記錄請(qǐng)求日志,以及支持可撤消的操作。

           

          看起來,命令模式好像神通廣大。其實(shí)命令模式的以上功能還要看你是怎么寫的——程序總是程序員寫出來的,你寫啥它才能干啥:)

           

                 在我看來,其實(shí)命令模式像很多設(shè)計(jì)模式一樣——通過在你的請(qǐng)求和處理之間加上了一個(gè)中間人的角色,來達(dá)到分離耦合的目的。通過對(duì)中間人角色的特殊設(shè)計(jì)來形成不同的模式。當(dāng)然命令模式就是一種特殊設(shè)計(jì)的結(jié)果。

           

                 看下命令模式是有哪些角色來組成的吧。             

           

          1)        命令角色(Command):聲明執(zhí)行操作的接口。有java接口或者抽象類來實(shí)現(xiàn)。

           

          2)        具體命令角色(Concrete Command):將一個(gè)接收者對(duì)象綁定于一個(gè)動(dòng)作;調(diào)用接收者相應(yīng)的操作,以實(shí)現(xiàn)命令角色聲明的執(zhí)行操作的接口。

           

          3)        客戶角色(Client):創(chuàng)建一個(gè)具體命令對(duì)象(并可以設(shè)定它的接收者)。

           

          4)        請(qǐng)求者角色(Invoker):調(diào)用命令對(duì)象執(zhí)行這個(gè)請(qǐng)求。

           

          5)        接收者角色(Receiver):知道如何實(shí)施與執(zhí)行一個(gè)請(qǐng)求相關(guān)的操作。任何類都可能作為一個(gè)接收者。

           

           

          以下是命令模式的類圖,從中可以大致的了解到各個(gè)角色之間是怎么來協(xié)調(diào)工作的。

           

           

           

          三、舉例

           

          本來想接著我的JUnit分析來講解命令模式。但是由于在JUnit中,參雜了其它的模式在里面,使得命令模式的特點(diǎn)不太明顯。所以這里將以命令模式在Web開發(fā)中最常見的應(yīng)用——Struts中Action的使用作為例子。

           

          在Struts中Action控制類是整個(gè)框架的核心,它連接著頁(yè)面請(qǐng)求和后臺(tái)業(yè)務(wù)邏輯處理。按照框架設(shè)計(jì),每一個(gè)繼承自Action的子類,都實(shí)現(xiàn)execute方法——調(diào)用后臺(tái)真正處理業(yè)務(wù)的對(duì)象來完成任務(wù)。

           

          注:繼承自DispatchAction的子類,則可以一個(gè)類里面處理多個(gè)類似的操作。這個(gè)在這不做討論。

           

                 下面我們將Struts中的各個(gè)類與命令模式中的角色對(duì)號(hào)入座。

           

                 先來看下命令角色——Action控制類

           

          public class Action {

                 ……

                   /*

                   *可以看出,Action中提供了兩個(gè)版本的執(zhí)行接口,而且實(shí)現(xiàn)了默認(rèn)的空實(shí)現(xiàn)。

                 
          */

          public ActionForward execute( ActionMapping mapping,

                                                            ActionForm form,

                                                            ServletRequest request,

                                                            ServletResponse response)

                  throws Exception {

                  try {

                      return execute(mapping, form, (HttpServletRequest) request,

                                               (HttpServletResponse) response);

                  } catch (ClassCastException e) {

                      return null;

                  }

              }

           

          public ActionForward execute( ActionMapping mapping,

                                                            ActionForm form,

                                                             HttpServletRequest request,

                                                            HttpServletResponse response)

                  throws Exception {

                  return null;

              }

          }

           

          下面的就是請(qǐng)求者角色,它僅僅負(fù)責(zé)調(diào)用命令角色執(zhí)行操作。

          public class RequestProcessor {

          ……

          protected ActionForward processActionPerform(HttpServletRequest request,

                                                                  HttpServletResponse response,

                                                                 Action action,

                                                                 ActionForm form,

                                                                 ActionMapping mapping)

                  throws IOException, ServletException {

                  try {

                      return (action.execute(mapping, form, request, response));

                  } catch (Exception e) {

                      return (processException(request, response,e, form, mapping));

                  }

          }

          }

           

          Struts框架為我們提供了以上兩個(gè)角色,要使用struts框架完成自己的業(yè)務(wù)邏輯,剩下的三個(gè)角色就要由我們自己來實(shí)現(xiàn)了。步驟如下:

          1)        很明顯我們要先實(shí)現(xiàn)一個(gè)Action的子類,并重寫execute方法。在此方法中調(diào)用業(yè)務(wù)模塊的相應(yīng)對(duì)象來完成任務(wù)。

          2)        實(shí)現(xiàn)處理業(yè)務(wù)的業(yè)務(wù)類。

          3)        配置struts-config.xml配置文件,將自己的Action和Form以及相應(yīng)頁(yè)面結(jié)合起來。

          4)        編寫jsp,在頁(yè)面中顯式的制定對(duì)應(yīng)的處理Action。

          一個(gè)完整的命令模式就介紹完了。當(dāng)你在頁(yè)面上提交請(qǐng)求后,Struts框架會(huì)根據(jù)配置文件中的定義,將你的Action對(duì)象作為參數(shù)傳遞給RequestProcessor類中的processActionPerform()方法,由此方法調(diào)用Action對(duì)象中的執(zhí)行方法,進(jìn)而調(diào)用業(yè)務(wù)層中的接收角色。這樣就完成了請(qǐng)求的處理。

           

          四、Undo、事務(wù)及延伸

           

          在定義中提到,命令模式支持可撤銷的操作。而在上面的舉例中并沒有體現(xiàn)出來。其實(shí)命令模式之所以能夠支持這種操作,完全得益于在請(qǐng)求者與接收者之間添加了中間角色。為了實(shí)現(xiàn)undo功能,首先需要一個(gè)歷史列表來保存已經(jīng)執(zhí)行過的具體命令角色對(duì)象;修改具體命令角色中的執(zhí)行方法,使它記錄更多的執(zhí)行細(xì)節(jié),并將自己放入歷史列表中;并在具體命令角色中添加undo方法,此方法根據(jù)記錄的執(zhí)行細(xì)節(jié)來復(fù)原狀態(tài)(很明顯,首先程序員要清楚怎么來實(shí)現(xiàn),因?yàn)樗蚭xecute的效果是一樣的)。

           

          同樣,redo功能也能夠照此實(shí)現(xiàn)。

           

          命令模式還有一個(gè)常見的用法就是執(zhí)行事務(wù)操作。這就是為什么命令模式還叫做事務(wù)模式的原因吧。它可以在請(qǐng)求被傳遞到接收者角色之前,檢驗(yàn)請(qǐng)求的正確性,甚至可以檢查和數(shù)據(jù)庫(kù)中數(shù)據(jù)的一致性,而且可以結(jié)合組合模式的結(jié)構(gòu),來一次執(zhí)行多個(gè)命令。

           

          使用命令模式不僅僅可以解除請(qǐng)求者和接收者之間的耦合,而且可以用來做批處理操作,這完全可以發(fā)揮你自己的想象——請(qǐng)求者發(fā)出的請(qǐng)求到達(dá)命令角色這里以后,先保存在一個(gè)列表中而不執(zhí)行;等到一定的業(yè)務(wù)需要時(shí),命令模式再將列表中全部的操作逐一執(zhí)行。

           

          哦,命令模式實(shí)在太靈活了。真是一個(gè)很有用的東西啊!

           

           

          五、優(yōu)點(diǎn)及適用情況

           

          由上面的講解可以看出命令模式有以下優(yōu)點(diǎn):

          1)        命令模式將調(diào)用操作的請(qǐng)求對(duì)象與知道如何實(shí)現(xiàn)該操作的接收對(duì)象解耦。

          2)        具體命令角色可以被不同的請(qǐng)求者角色重用。

          3)        你可將多個(gè)命令裝配成一個(gè)復(fù)合命令。

          4)        增加新的具體命令角色很容易,因?yàn)檫@無需改變已有的類。

          GOF總結(jié)了命令模式的以下適用環(huán)境。

          1)        需要抽象出待執(zhí)行的動(dòng)作,然后以參數(shù)的形式提供出來——類似于過程設(shè)計(jì)中的回調(diào)機(jī)制。而命令模式正是回調(diào)機(jī)制的一個(gè)面向?qū)ο蟮奶娲贰?br />
          2)        在不同的時(shí)刻指定、排列和執(zhí)行請(qǐng)求。一個(gè)命令對(duì)象可以有與初始請(qǐng)求無關(guān)的生存期。

          3)        需要支持取消操作。

          4)        支持修改日志功能。這樣當(dāng)系統(tǒng)崩潰時(shí),這些修改可以被重做一遍。

          5)        需要支持事務(wù)操作。

           

          六、總結(jié)

           

          命令模式是一個(gè)很有用的模式,希望這篇文章能給你實(shí)質(zhì)性的幫助。謝謝大家指正。 v

           
          posted on 2012-10-24 18:04 abing 閱讀(263) 評(píng)論(0)  編輯  收藏 所屬分類: mode

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 平昌县| 朝阳县| 金坛市| 泰安市| 囊谦县| 南江县| 枞阳县| 桐城市| 榆林市| 洪泽县| 池州市| 云南省| 芮城县| 惠州市| 沐川县| 余庆县| 彩票| 榆社县| 讷河市| 静乐县| 承德市| 镇沅| 故城县| 沙田区| 子长县| 汉中市| 霞浦县| 若羌县| 房产| 青川县| 牙克石市| 苏州市| 巴里| 东源县| 科技| 饶河县| 安徽省| 兴仁县| 阿合奇县| 沁阳市| 乡城县|