Live a simple life

          沉默(zhu_xing@live.cn)
          隨筆 - 48, 文章 - 0, 評論 - 132, 引用 - 0
          數(shù)據(jù)加載中……

          【設計模式】有關(guān)策略模式

                  對于工廠、策略、命令、適配、模版方法等模式大家應該都非常清楚了,因為這是使用極其頻繁的一些模式。如果對于設計模式不是很清楚,估計也應該是在無形中使用了。剛review一塊代碼,想起和策略模式使用的時候的幾個問題,僅供大家參考。
                  說明:本人對設計模式理解很有限,工作經(jīng)驗也不長,歡迎指正,謝絕諷刺、挖苦^_^

                  【策略模式的本質(zhì)】
                     如果先來無事想一下經(jīng)典的23個OO設計模式,部分其實就是在良好地利用繼承,部分則是避免繼承,當然是否使用繼承是由技術(shù)需求決定的。“繼承封裝變化”這句話聽的耳朵都起繭子了,繼承是多態(tài)的結(jié)構(gòu)基礎(chǔ),多態(tài)特性給予了針對不同實例對同一請求做出不同反應的能力。我們在遇到可變的點時候,一般處理如下:
                  1、對可變點抽象出一個共性的概念,用繼承封裝這種變化
                  2、在客戶端以引用的方式使用這種概念
                  很顯然,上面1的結(jié)果是產(chǎn)生抽象類型(往往是對外暴露,基于接口),并繼承產(chǎn)生一系列擴展實現(xiàn)(往往是作為擴展實現(xiàn),不一定對外暴露),上面2則需要我們思考如何構(gòu)造實例,推薦的是講類型本身和類型實例的構(gòu)造進行分離(是客戶端自己構(gòu)造,還是有個工廠類型的角色來負責這種構(gòu)造?如果有個工廠的角色來承擔實例化的任務,那么這些擴展實現(xiàn)則跟容易隱藏)。
                  『PS:我們常說的基于接口編程,但是接口本身必然是不能實例化的,那么是用戶訪問具體實現(xiàn)類型構(gòu)造函數(shù)來實例化呢,還是從一個工廠中去取呢? 當然,理論上后者更好,也是基于接口編程的重要保證手段!』
                  我們的策略模式精髓是:將算法(特定類型行為邏輯)封裝進對象,便于獨立使用。廣義的講,處理上面說的變化的點的手段有很多種,策略模式是其中之一,設計模式是工具層面^_^ (需求中變化的點如何處理,策略模式可能用的上,絕對不是想用策略模式,去產(chǎn)生一些變化的點)。但是,使用策略模式的經(jīng)驗告訴我們,定義的算法接口經(jīng)常要修改...

                  【策略模式使用時候的幾個疑問】
                  先說幾個疑問:1、數(shù)據(jù)上下文合理嗎;2、策略本身是否需要實例狀態(tài);3、如何實例化和管理這些策略;4、行為控制上下文如何處理

                  場景:構(gòu)建一個電子商務系統(tǒng),要處理不同地區(qū)的業(yè)務,地區(qū)不同業(yè)務處理規(guī)則可能有點區(qū)別。

                  很自然的,我們剛開始定義如下的接口(就叫做IPolicy吧 ~_~):
          1 public interface IPolicy {
          2     public boolean process(String id, String account);
          3 }
                 上面的id、account等參數(shù)就是我們處理一個訂單需要的參數(shù),也是從一個請求(Requst)數(shù)據(jù)結(jié)構(gòu)中的部分信息。到這里,感覺一起OK。

                  數(shù)據(jù)上下文合理呢?
                  這個疑問出來,才回想起來,在定義IPolicy接口的時候,對process操作接受的數(shù)據(jù)上下文并沒有進行足夠的分析。可能就是假借一個地區(qū)的訂單處理想了一下,處理一個訂單需要這些信息。
                  隨著新地區(qū)訂單策略實現(xiàn)的加入,最有可能帶來的一個問題就是:你的process給的參數(shù)信息不夠!!!一旦不夠,那么你要修改的就是接口定義了,這個時候可能已經(jīng)有一些策略實現(xiàn)了,修改吧!!!
                  對IPolicy接口修改如下:
          1 public interface IPolicy {
          2     public boolean process(Request request);
          3 }
                  這里的Request是從系統(tǒng)接受到的請求(假設是從一個web service過來的,上面的id、account就是從Request中獲取來的),那么Request里面的信息一般來說對于處理一個請求是足夠的了, 這樣你定義的IPolicy就更能夠應對數(shù)據(jù)上下文的變化了。

                  如何實例化和管理這些策略?誰承擔這個責任?
                  假設,有了兩個實現(xiàn),分別針對A區(qū)域和B區(qū)域:   
          1 public class RegionAPolicy implements IPolicy {
          2     
          3     public boolean process(Request request) {
          4         //
          5         return true;
          6     }
          7 }
                  
          1 public class RegionBPolicy implements IPolicy {
          2     
          3     public boolean process(Request request) {
          4         //
          5         return true;
          6     }
          7 }
                  
                  假設,現(xiàn)在客戶端如下使用:
           1 //
           2         String region = requst.getRegion();
           3         if ("A".equalsIgnoreCase(region)) {
           4             IPolicy policy = new RegionAPolicy();
           5             boolean result = policy.process(request);
           6             //
           7         }
           8         else if ("B".equalsIgnoreCase(region)) {
           9             IPolicy policy = new RegionBPolicy();
          10             boolean result = policy.process(request);
          11             //
          12         }
          13         //
                     客戶端首先獲取對應的region信息,然后if else去創(chuàng)建對應的策略實例,然后再去調(diào)用這些實例上的服務.......那如果有個中間角色來管理這些策略,是不是能夠把類型的使用和類型的實例化分開呢?引入一個管理器角色看一下:
          1 public class PolicyManager {
          2     private PolicyManager() {}
          3     
          4     public static PolicyManager getInstance() {//}
          5     
          6     public IPolicy getPolicy(String region) {//}
          7 
          8 }
                  
                  客戶端調(diào)用代碼變?yōu)槿缦拢?br />
          1        //
          2         String region = requst.getRegion();
          3         IPolicy policy = PolicyManager.getInstance().getPolicy(region);
          4         boolean result = policy.process(request);
          5         //
                  比較前面的調(diào)用代碼,我們發(fā)現(xiàn),客戶端少干了一件事情:實例化和管理實例!!!  而且這樣也可以做到具體的Policy實現(xiàn)類型對客戶端隱藏,客戶端真正基于接口。上面的PolicyManager我并沒有具體寫如何管理實例,在本問題場景下,只要保證一點就可以了,用戶找你這個manager去獲取指定region的策略。~_~

                  策略對象需要實例狀態(tài)嗎?可以當作單態(tài)處理嗎?需要同步化嗎?
                  需要分析你的策略,準確地判斷你的策略實例是否需要實例字段來表示狀態(tài)。一般是不需要的~_~ 如果引入實例變量,你的策略要有相應的管理...
                 如果可以認為是單太的,那么同步化...

                  控制上下文如何設計...?
                  你的策略如何面對異常情況?例如發(fā)生異常時怎么辦?異常信息又如何處理?是否可以把異常信息都收集起來呢,這樣可以針對這些異常信息做各種處理  等等
                  例如,可能將接口調(diào)整如下:
                  
          1 public interface IMessageCollector {
          2     public void reportError();
          3     
          4     public void reportWarning();
          5 }

          1 public interface IPolicy {
          2     public boolean process(Object request, IMessageCollector collector);
          3 }
                  
                  
           1 //
           2         IMessageCollector messageCollector = new MessageCollectorImpl();
           3         
           4         String region = requst.getRegion();
           5         IPolicy policy = PolicyManager.getInstance().getPolicy(region);
           6         boolean result = policy.process(request, messageCollector);
           7         
           8         if (!result) {
           9             //TODO:處理messageCollector的一些錯誤和警告信息等
          10         }
          11         //

                  這樣我們的異常信息的就可以集中管理,可以在客戶端做各種處理,而不需要修改策略本身,加強策略本身的復用。


                  后記
                  既然我們使用策略來封裝策略變化,那么我們應該也要思考如何讓我們的策略減少修改、易于擴展。其實如何將設計模式和一些基本的OO設計原則合理配合,在原則的指導下去用設計模式這個工具...是個很大的話題,不知道怎么去說。

                  以上寫的是一點自己的感想,大家有什么好的意見,敬請分享一下。文中的示意代碼僅僅是為了輔助說明問題~_~

          本博客中的所有文章、隨筆除了標題中含有引用或者轉(zhuǎn)載字樣的,其他均為原創(chuàng)。轉(zhuǎn)載請注明出處,謝謝!

          posted on 2008-09-03 11:41 zhuxing 閱讀(1552) 評論(3)  編輯  收藏 所屬分類: Java設計

          評論

          # re: 【設計模式】有關(guān)策略模式  回復  更多評論   

          不錯,寫的有道理,非常贊同一些觀點!
          2008-09-03 13:14 | Jack.Wang

          # re: 【設計模式】有關(guān)策略模式  回復  更多評論   

          > 數(shù)據(jù)上下文合理嗎?

          結(jié)合采用command模式。
          2008-09-04 00:44 | linuxer

          # re: 【設計模式】有關(guān)策略模式  回復  更多評論   

          @linuxer
          你說的是一種辦法,在很多場景下可以這么做。我寫這篇隨筆的時候,就想集中精力來看一下一個行為封裝伴隨的上下文問題...
          2008-09-04 10:03 | zhuxing
          主站蜘蛛池模板: 广灵县| 新河县| 峨眉山市| 布拖县| 松潘县| 健康| 西平县| 板桥市| 中西区| 民和| 鄂托克前旗| 鲁山县| 西平县| 广饶县| 赣州市| 土默特左旗| 乌审旗| 寻甸| 丹江口市| 苏州市| 五大连池市| 临夏县| 雷州市| 时尚| 重庆市| 松江区| 南宁市| 临漳县| 嘉善县| 施甸县| 定襄县| 扬中市| 赤水市| 鄯善县| 晋州市| 秀山| 巴林左旗| 深州市| 宜兰县| 永胜县| 江北区|