<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    zxbyhcsdn

     

    關(guān)于工廠方法模式與開閉原則

    這兒有兩個(gè)關(guān)鍵點(diǎn):

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

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

    但是我認(rèn)為它并不滿足開閉, 不知道是不是我的認(rèn)識有錯(cuò)誤
    故再此發(fā)文一篇,權(quán)當(dāng)討論與提高.

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

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

    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{
         //聲明一個(gè)變量引用
         ITest test = null;

         //根據(jù)用戶輸入決定實(shí)例化具體的對象
         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 具體的類,不滿足開閉原則

    因?yàn)樾薷幕蛘咴黾樱琻ew這個(gè)地方都要改動(dòng)
    比如說我們現(xiàn)在增加了一個(gè)類C,那么客戶端這兒就不可避免要改動(dòng).
    如果這樣的邏輯在多個(gè)客戶端用到,就必須都做改動(dòng),顯然是不合理的.

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

    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;
        }
    }

    然后客戶端調(diào)用改為:

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

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

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

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

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

    interface IFactoryMathod{
        ITest create();
    }

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

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

    然后 客戶端調(diào)用變成:

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

        //根據(jù)用戶輸入決定實(shí)例化具體的對象
        BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
        String line = sin.readLine();
      
        //調(diào)用工廠方法創(chuàng)建對象
        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());
        }
    }

    但是現(xiàn)在問題有來了,客戶端的這段代碼又瓜了.對客戶端來說,又不滿足開閉了.
    我們轉(zhuǎn)了一圈結(jié)果發(fā)現(xiàn)又回到開始的地方了...暈??

    哪么我認(rèn)為:工廠方法仍然不滿足開閉, 因?yàn)橹灰诖a里面用了New ,就不可能滿足開閉,如果有添加
    總要修改到現(xiàn)有代碼的某一個(gè)部分.

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

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

    哪么就進(jìn)入下面的一個(gè)論點(diǎn): 工廠方法的使用場合

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

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

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

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

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

    工廠方法模式并不是因?yàn)楹唵喂S方法不滿足開閉原則而引入
    而是因?yàn)?類的構(gòu)造邏輯復(fù)雜且多變,為了將構(gòu)造邏輯封裝而引入


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


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


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

     

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

    評論

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

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

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

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

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

    @LB

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

    本人也認(rèn)為,原則是死的,使用的人是靈活的..

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

      回復(fù)  更多評論   

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

    個(gè)人覺得摟主文章里面對“開閉原則”的理解有點(diǎn)狹隘

    首先,開閉原則本身重在強(qiáng)調(diào)系統(tǒng)真?zhèn)€框架在引入新擴(kuò)展的時(shí)候能夠提供比較自然的擴(kuò)展,外部使用的抽象層面的東西不需要做很大的改動(dòng)。而且,從本質(zhì)上將,開閉原則也有一定的成分是愿景,不然就不會(huì)將其提高到了OO編程5大原則之一了

    其次,客戶端的調(diào)用代碼的需要改動(dòng),是不是據(jù)此就判斷是打破了開閉原則了。個(gè)人覺得不是這樣的。

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


    個(gè)人意見,僅供參考!

    同時(shí)贊同樓上@LB評論的觀點(diǎn)


      回復(fù)  更多評論   


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


    網(wǎng)站導(dǎo)航:
     

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(1)

    隨筆分類

    隨筆檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 国产午夜鲁丝片AV无码免费| 久久免费观看视频| 2020天堂在线亚洲精品专区| 久久久久久久亚洲Av无码| 久久精品国产精品亚洲艾草网| 亚洲熟妇无码乱子AV电影| 亚洲综合av永久无码精品一区二区 | MM131亚洲国产美女久久| 四只虎免费永久观看| 亚洲精品97久久中文字幕无码| 亚洲精品乱码久久久久久蜜桃 | 永久黄网站色视频免费观看| 国产成人免费福利网站| 国产jizzjizz免费看jizz| 四虎国产精品免费久久影院| 亚洲AV无码成H人在线观看 | 成年女人色毛片免费看| 免费观看一级毛片| 免费一级毛片正在播放| 国产亚洲精品AA片在线观看不加载| 综合亚洲伊人午夜网| 亚洲va久久久噜噜噜久久| 亚洲麻豆精品果冻传媒| 2019亚洲午夜无码天堂| 特黄aa级毛片免费视频播放| XXX2高清在线观看免费视频| 日本在线免费观看| 18禁免费无码无遮挡不卡网站| 女人张开腿等男人桶免费视频| 免费夜色污私人影院在线观看| 337p日本欧洲亚洲大胆裸体艺术| 亚洲av中文无码乱人伦在线咪咕| 亚洲电影免费观看| 亚洲av永久无码精品秋霞电影秋 | 免费看男女下面日出水来| 四虎成人精品一区二区免费网站| 啊灬啊灬别停啊灬用力啊免费看| 亚洲人精品午夜射精日韩| 亚洲日韩乱码中文无码蜜桃 | 亚洲xxxx18| 在线播放国产不卡免费视频|