zxbyhcsdn

           

          關于工廠方法模式與開閉原則

          這兒有兩個關鍵點:

          1>工廠方法滿足開閉原則么?
          2>工廠方法到底用在什么場合?

          好像模式的書上都寫著工廠方法滿足開閉原則...

          但是我認為它并不滿足開閉, 不知道是不是我的認識有錯誤
          故再此發文一篇,權當討論與提高.

          哪么先從簡單工廠說起,好像所有的講設計模式的書籍里面工廠模式都是從簡單工廠開始的.
          簡單工廠是公認的部分支持開閉原則的.

          眾所周知工廠模式就是為了解決New這個玩意兒的,先來一個沒有用到工廠的例子

          import java.io.*;
          interface ITest{
              String testFun();
          }
          class TestA implements ITest{
              public String testFun(){
                  return "A;testFun";
              }
          }
          class TestB implements ITest{
              public String testFun(){
                  return "B;testFun";
              }
          }

          public class TestFactory{
              public static void main(String args[]) throws IOException{
               //聲明一個變量引用
               ITest test = null;

               //根據用戶輸入決定實例化具體的對象
               BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
               String line = sin.readLine();
                if(line.equals("A")){
                  test = new TestA();
               }
               else if(line.equals("B")){
                  test = new TestB();
               }
               //使用對象
               if (test != null){
               System.out.println(test.testFun());
               }
             }
          }


          這兒使用了 new 具體的類,不滿足開閉原則

          因為修改或者增加,new這個地方都要改動
          比如說我們現在增加了一個類C,那么客戶端這兒就不可避免要改動.
          如果這樣的邏輯在多個客戶端用到,就必須都做改動,顯然是不合理的.

          基于 "對可變性的封裝" 的指導思想.
          把new這個地方的工作封裝到一個類里面,于是就有了簡單工廠.

          class SampleFactory{
              public static ITest create(String ar){
                  if(ar.equals("A")){
                      return new TestA();
                  }
                  else if(ar.equals("B")){
                      return new TestB();
                  }
                  return null;
              }
          }

          然后客戶端調用改為:

          public static void main(String args[]) throws IOException{
              //聲明一個變量引用
              ITest test = null;

              //根據用戶輸入決定實例化具體的對象
              BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
              String line = sin.readLine();
            
              //調用簡單工廠創建對象
              test = SampleFactory.create(line);

              //使用對象
              if (test != null){
                  System.out.println(test.testFun());
              }
          }

          于是這兒就能適應變化了,如果新加入了C類型,就不用去修改所有使用的客戶端了.客戶端滿足開閉了,
          但是工廠又必須修改,而且吧其他類型的創建邏輯影響到了.那咋辦捏?

          又基于"對可變性的封裝" 的指導思想,對每一個類型的New 都弄一個工廠,這樣有擴展就不得影響
          道其他工廠了, 這個就是工廠方法模式, 好像滿足了 開閉原則了,

          interface IFactoryMathod{
              ITest create();
          }

          class FactoryA implements IFactoryMathod{
           public ITest create(){
                  return new TestA();
           }
          }

          class FactoryB implements IFactoryMathod{
           public ITest create(){
                  return new TestB();
           }
          }

          然后 客戶端調用變成:

          public static void main(String args[]) throws IOException{
              //聲明一個變量引用
              ITest test = null;
              //聲明一個工廠
              IFactoryMathod factory = null;

              //根據用戶輸入決定實例化具體的對象
              BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
              String line = sin.readLine();
            
              //調用工廠方法創建對象
              if(line.equals("A")){
                  factory = new FactoryA();
              }
              else if(line.equals("B")){
                  factory = new FactoryB();
              }
              else{
                  factory = new FactoryB();
              }
              test = factory.create();
              //使用對象
              if (test != null){
                  System.out.println(test.testFun());
              }
          }

          但是現在問題有來了,客戶端的這段代碼又瓜了.對客戶端來說,又不滿足開閉了.
          我們轉了一圈結果發現又回到開始的地方了...暈??

          哪么我認為:工廠方法仍然不滿足開閉, 因為只要在代碼里面用了New ,就不可能滿足開閉,如果有添加
          總要修改到現有代碼的某一個部分.

          這兒就需要引入反射,消除了New,從配置文件里面讀取需要創建的對象.比如說Spring就是這么干的.

          然后說了半天,從上面的這個例子好像發現,那個工廠方法沒什么用處得,完全就是用一個方法把new
          包起來,大大的有脫褲子放屁的嫌疑..
          到底怎么回事情啦,不可能大名頂頂的工廠方法就這樣子??

          哪么就進入下面的一個論點: 工廠方法的使用場合

          好像有了反射.工廠方法就可以下崗了...
          的確,我認為僅僅在工廠方法里面寫一個New XXXX 的話,哪么這樣用工廠方法的確快下崗了..

          但是我覺得真正體現工廠方法的意義的在這兒:
          還是 拿出 我們的指導思想(馬克思列寧思想...哈哈哈) "對可變性的封裝"
          當對象的創建不僅僅是一個new XXXX,包含復雜的業務邏輯,而且可以面臨巨大的變動.
          比如說: 有個需求是對象的創建需要是從文件序列化出來,如果沒有才New一個,屬性設置為默認,
          萬一那天有要求分布式應用,不能從文件里面反序列,需要改為從數據庫里面找到屬性并創建一個出來.
          總不可能在每個調用這個類的客戶端端口都去寫上這么一大堆 if else的業務邏輯三.
          如果以后再有改動,不就麻煩了..

          這個時候就需要工廠方法,把可變的封裝到工廠方法里面,
          如果以后有變動或者增加,我們就只是需要修改或者擴展具體的工廠方法類,其他的都不會受到干擾.
          再結合反射,將工廠方法類放到配置文件,這樣就能真正的 滿足開閉原則.

          可能有同學有提出來問題:我何不在具體類的構造函數里面去做哪么一大堆啦.這樣有改動的化,
          我修改一下那個構造函數不久得了.反正用了反射,仍然滿足開閉原則.

          但是如果那個地方的代碼變動的可能很大,你修改了構造函數,哪么這個類的其他地方就受到干擾了
          站在這個問題的角度說,就是: 當一個類的構造邏輯頻繁變動,哪么就需要把他封裝,于是把這兒的邏輯放到工廠方法里面了.
          這兒有體現了 "對可變性的封裝" 的思想

          工廠方法模式并不是因為簡單工廠方法不滿足開閉原則而引入
          而是因為:類的構造邏輯復雜且多變,為了將構造邏輯封裝而引入


          哪么現在得出結論:
          1>工廠方法并不真正滿足開閉原則,但是結合反射和配置文件能夠滿足.
          2>工廠方法使用場合 : 類的構造邏輯復雜且多變,為了將構造邏輯封裝而引入
          如果僅僅是在工廠方法里面寫一個New,而且也不會發生變化.就沒有使用工廠方法的意義了.


          然后還有這個 思想我覺得比較重要
          "對可變性的封裝",或者說 "對不確定性的封裝"
          OOAD的核心思想啊!!!


          歡迎討論...寫這些的目的就是為了共同進步,有什么錯誤或者不足,歡迎指出....

           

          posted on 2008-07-26 21:31 zxbyh 閱讀(2386) 評論(3)  編輯  收藏 所屬分類: 設計模式

          評論

          # re: 關于工廠方法模式與開閉原則[未登錄] 2008-07-26 22:03 LB

          理論結合實際,等你真正做系統時候,沒有那么多完美的情況。
          還有選擇最適合的方法,不是說spring出來了就處處用spring,或者處處都AOP,反射用在需要的地方,你可以去IBM development那里看看專家評測的new一個對象和用反射建立一個對象時間消耗,都不在一個級別上。

          另外,你的factory不用還為每一個類型在建立具體的factory,那個和直接建立這個類型有什么區別,就是多了一個中間層環節,可是你只是new,并沒有加入任何邏輯型的東西。所以說,你具的例子太不實際了。

          寫這些思想的人,也是一開始自己摸索的,他提出來了,也是他盡量地總結出來的,怎么現在的程序員腦子這么死性呢!  回復  更多評論   

          # re: 關于工廠方法模式與開閉原則 2008-07-26 22:19 zxbyh

          @LB

          本文是在討論 工廠模式與開閉原則.
          并不是在討論實際系統是否必須百分百滿足開閉原則.

          本人也認為,原則是死的,使用的人是靈活的..

          還有一點,我舉例的factory為每一個類型在建立具體的factory,
          這個正是我要論證的論點:如果僅僅是在工廠方法里面寫一個New,而且也不會發生變化.就沒有使用工廠方法的意義了.
          可以認為那是一個反例!!!

            回復  更多評論   

          # re: 關于工廠方法模式與開閉原則 2008-07-28 13:30 zhuxing

          個人覺得摟主文章里面對“開閉原則”的理解有點狹隘

          首先,開閉原則本身重在強調系統真個框架在引入新擴展的時候能夠提供比較自然的擴展,外部使用的抽象層面的東西不需要做很大的改動。而且,從本質上將,開閉原則也有一定的成分是愿景,不然就不會將其提高到了OO編程5大原則之一了

          其次,客戶端的調用代碼的需要改動,是不是據此就判斷是打破了開閉原則了。個人覺得不是這樣的。

          估計樓主是在客戶端代碼里面包含了一定的選擇特定工廠的任務,覺得新工廠的進入,需要增加判斷語句,以便使用新的工廠實現。進一步延伸講,這只是一個客戶端,真正的系統中可能有很多很多的類似客戶端。如果講工廠的選擇操作做一個封裝,那多個客戶端選擇工廠的行為操作本身就可以進行封裝了,例如:
          getFactory(int factoryID) {//...}


          個人意見,僅供參考!

          同時贊同樓上@LB評論的觀點


            回復  更多評論   


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          導航

          統計

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 新兴县| 阳山县| 贵定县| 井陉县| 宣城市| 禄丰县| 四子王旗| 横山县| 普洱| 井陉县| 丰原市| 新源县| 策勒县| 呼图壁县| 东城区| 阿克陶县| 独山县| 来凤县| 辽宁省| 禄劝| 武山县| 楚雄市| 潍坊市| 临漳县| 桂平市| 敦化市| 怀柔区| 德兴市| 当雄县| 舟山市| 桂平市| 河津市| 高密市| 贡嘎县| 安吉县| 遂川县| 来凤县| 慈利县| 昭觉县| 左云县| 丹阳市|