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

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

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

    zming

    Java tech JMX Aop Ioc WebUI....

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      25 隨筆 :: 0 文章 :: 3 評論 :: 0 Trackbacks
     

    翻譯作者:zming

    翻譯自:http://today.java.net/pub/a/today/2005/04/14/dependency.html

    轉載請注明出處:http://blog.csdn.net/zmxj/archive/2005/05/25/380784.aspx

    <<Head First Design Patterns>>一書的Factory 模式章節中,建議我們要“Breaking the Last Dependency”,即打破最后的依賴,并且展示了如何寫出完全遠離具體類的代碼。下面我們來看看這個主題。

    看看breaking the last dependency 是什么意思?它是如何來描述工廠模式的?以及我們為什么應該關注它?所有的工廠模式都是封裝具體類的實例并幫助你將代碼和具體類的依賴減少到最少。看下面的代碼:

    public class StampedeSimulator {

        Actor actor = null;

        public void addActor(String type) {

            if (type.equals("buffalo")) {

                actor = new Buffalo();

            } else if (type.equals("horse")) {

                actor = new Horse();

            } else if (type.equals("cowboy")) {

                actor = new Cowboy();

            } else if (type.equals("cowgirl")) {

                actor = new Cowgirl();

            }

            // rest of simulator here

        }

    }

    這段代碼中包含了四個不同的具體類(Buffalo, Horse, Cowboy, and Cowgirl)結果他建立了依賴關系在你的代碼和這些具體類之間,這為什么是一件壞事呢?你想想,如果你要加入一個新的類型(比如Coyote)或者重新配置具體類(比如你想用FastHorse類替代普通的Horse類),你將重新修改你的代碼,這造成難維護性。切記,可能類似的代碼會遍布你的所有代碼中,如果你要修改這個代碼需要到多處修改。注意我們不要寄希望于Java5.0enumerations匹配字符串來減少這些代碼,不是所有的用戶都可以在Java5平臺下的(比如蘋果系統的用戶),我們將作其他的實踐。

        現在我們有沒有一個好的方法減少具體類的依賴呢?那將使你的生活更加輕松,減少你大量的代碼維護工作,辦法就是使用Factory.有幾種類型的工廠,用哪一種你可以查相關的模式書。為了我們的事例,讓我們看看Static Factory,它由一個類組成,它提供一個靜態方法來操縱一個對象的實例。要實現這個,我們將所有實例代碼放到一個factory里,ActorFactory,替換上面StampedeSimulator代碼,用factory來創建對象:

    public class ActorFactory {
        
    static public Actor createBuffalo() {
            
    return new Buffalo();
        }

        
    static public Actor createHorse() {
            
    return new Horse();
        }

        
    static public Actor createCowboy() {
            
    return new Cowboy();
        }

        
    static public Actor createCowgirl() {
            
    return new Cowgirl();
        }

    }

    And we can alter our StampedeSimulator to look like 
    this
     
    public class StampedeSimulator {
        Actor actor 
    = null;
     
        
    public void addActor(String type) {
            
    if (type.equals("buffalo")) {
                actor 
    = ActorFactory.createBuffalo();
            }
     else if (type.equals("horse")) {
                actor 
    = ActorFactory.createHorse();
            }
     else if (type.equals("cowboy")) {
                actor 
    = ActorFactory.createCowboy();
            }
     else if (type.equals("cowgirl")) {
                actor 
    = ActorFactory.createCowgirl();
            }

     
            
    // rest of stampede simulator here
        }

    }

    僅這樣只是得到了一點改善,因為代碼中還有兩個if else then子句。我們還可以進一步改進,我們來參數化工廠,用一個String來標示具體實例的類型:

    僅這樣只是得到了一點改善,因為代碼中還有兩個if else then子句。我們還可以進一步改進,我們來參數化工廠,用一個String來標示具體實例的類型:

    public class ActorFactory {

        static public Actor createActor(String type) {

            if (type.equals("buffalo")) {

                return new Buffalo();

            } else if (type.equals("horse")) {

                return new Horse();

            } else if (type.equals("cowboy")) {

                return new Cowboy();

            } else if (type.equals("cowgirl")) {

                return new Cowgirl();

            } else {

                return null;

            }

        }

    }

     

    public class StampedeSimulator {

        Actor actor = null;

        public void addActor(String type) {

            actor = ActorFactory.createActor(type);

            // rest of stampede simulator here

        }

    }

     

    現在我們已經很好分離了具體類和我們的代碼中的依賴。注意,工廠中的方法的返回類型是一個接口(Actor)或者也可以是一個抽象類。這使得你的客戶端不需要知道具體的類是什么,因而,在你的客戶端代碼里使用接口,你將繼續解耦和你的具體類的依賴。靜態工廠創建你需要的對象,你的客戶端代碼不需要擔心它。現在,如果你需要改變代碼,你只需要去一個地方,實例都被封裝了。

       這樣把具體類封裝到工廠中是很好的事,我們解耦了主要代碼和具體類之間的依賴。但是工廠本身仍然依賴于具體的類,如果我們需要改變那些類,就是說需要修改工廠的代碼,重新編譯,那樣不是我們想要做的,我們希望移除所有這樣的依賴在我們的代碼里。

        在我們繼續之前,我要指出靜態工廠(Static Factory是一種經常被使用的超過真正的設計模式的慣用方法,但是象這樣使用的人常常用單詞“工廠(Factory)”來應用這個創建對象的方法. 無論如何,你能使用我們正要結束的靜態工廠或者仍何使用真正的工廠模式的技術(like the Factory Method or Abstract Factory patterns).

        在我們繼續之前,我要指出靜態工廠(Static Factory是一種經常被使用的超過真正的設計模式的慣用方法,但是象這樣使用的人常常用單詞“工廠(Factory)”來應用這個創建對象的方法. 無論如何,你能使用我們正要結束的靜態工廠或者仍何使用真正的工廠模式的技術(like the Factory Method or Abstract Factory patterns).

        在我們繼續之前,我要指出靜態工廠(Static Factory是一種經常被使用的超過真正的設計模式的慣用方法,但是象這樣使用的人常常用單詞“工廠(Factory)”來應用這個創建對象的方法. 無論如何,你能使用我們正要結束的靜態工廠或者仍何使用真正的工廠模式的技術(like the Factory Method or Abstract Factory patterns).

    Let's Break that Last Dependency

    (讓我們打破最后的依賴)

    我們解耦了應用主要代碼和具體類的依賴,但是Static Factory, ActorFactory仍然牢牢地綁定著具體的類,加之丑陋的if-then-else語句仍然存在。我們如何才能改善這些移除最后的依賴呢?

        有一種技術是使用javaClass.forName()forName()方法允許你用指定的包路徑下的類名動態的裝入類。一旦你要取得類,你只需要用實例化一個它的新實例,并且返回它。 讓我們看他怎樣工作:

    class ActorFactory {

        static public Actor createActor(String type) {

             Actor actor = null;

            Class actorClass = null;

            try {

                actorClass = Class.forName(type);

            } catch (ClassNotFoundException e) {

                System.out.println("Error: class " + type + " not found.");

                e.printStackTrace();

            } catch (Exception e) {

                e.printStackTrace();

            }

            if (actorClass != null) {

                try {

                    actor = (Actor) actorClass.newInstance();

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }

            return actor;

        }

    }

     

        這個代碼更加解耦了你的應用和具體類的依賴,因為現在你可以通過傳遞類名(或至少一些實現了Actor接口的類)給工廠,你就可以取得類的實例。我們為此付出的代價就是我們不得不檢測所有可能的途徑:首先,確信我們傳遞的類名字串的類事實存在,并且確信你能夠實例化這個類,我們可以在這偷個懶,我們可以在不能裝入或實例化一個類而發生異常時,打印出異常的stacktrace在實際應用中,顯然你不得不做的更多。我們也用靈活性換取了少許對靜態類型檢測的控制。你將要通過稍微的思考,對于實例,它能夠完美的合法的為我們裝入Actor類,但是我們不能實際上從Actor實例一個對象,因為他是一個接口。

       一旦我們修改了ActorFactory,我們需要在你的應用代碼里做一些小的修改,我們需要傳遞由String描述的actor類。像這樣:

        simulator.addActor("headfirst.factory.simulator.Buffalo");

        simulator.addActor("headfirst.factory.simulator.Horse");

        simulator.addActor("headfirst.factory.simulator.Cowboy");

        simulator.addActor("headfirst.factory.simulator.Cowgirl");

    像這樣,我們能夠編譯和運行這個代碼并且和先前得到相同的結果:每一個actor類型被實例化了。

       現在,當我們想要改變stampede simulatoractors時(例如,我們要拍一個電影,用動畫的演員替換真實的演員),所有要做的就是改變我們傳遞給addActor()方法的描述actor類型的String串即可。我們根本不需要改變ActorFactory or StampedeSimulator中的任何代碼。

    Taking It All the Way

    這是一個改進,但是代碼仍然和在actors的指定類型偶合,我們仍然需要指定在代碼中和傳遞給addActor()方法的Actor 類型的名字,意思就是當我們要改變演員的時候不得不重新編譯代碼,有什么其他的方法取得演員的類型,而沒有代碼依賴我們想要的演員的類型嗎?

    有一個辦法就是我們刪除所有依賴具體類型的代碼,指定我們想要的actors的類型在一個properties文件,在運行時裝入他們。這樣我們就沒有依賴具體演員類型的代碼了。這樣做,我們改變指定的演員類型。替換硬編碼actor類型,用編碼載入類型從一個叫做actor.propertiesproperties文件。這個文件每行是你需要的一個演員類型,看起來像這樣:

    buffalo = headfirst.factory.simulator.Buffalo

    buffalo = headfirst.factory.simulator.Buffalo

    buffalo = headfirst.factory.simulator.Buffalo

    horse = headfirst.factory.simulator.Horse

    cowboy = headfirst.factory.simulator.Cowboy

    cowgirl = headfirst.factory.simulator.Cowgirl

    這是一個標準格式的java properties文件:等號兩邊分別是屬性名和屬性值。現在可以替換傳遞給createActor()方法的actor的類型的完整路徑名,我們只要傳遞一個描述類型的串給他(就象我們的第一個版本中代碼那樣),這個串將對應于properties文件中的屬性名:

        simulator.addActor("buffalo");

        simulator.addActor("horse");

        simulator.addActor("cowboy");

        simulator.addActor("cowgirl");

     

    我們同樣需要修改ActorFactorycreateActor()方法,從properties文件中裝入所有的屬性到一個Properties實例中。然后傳遞類型給createActor()方法(例如:”buffalo”),取得屬性對應的actor的完整類型名,并用它實例化成我們需要的actor對象。

      
      static public Actor createActor(String type) {

            Class actorClass = null;

            Actor actor = null;

            String actorType = null;

            Properties properties = new Properties();

     

            try {

                properties.load(new FileInputStream("simulator.properties"));

            } catch (IOException e) {

                System.out.println("Error: couldn't read from the simulator.properties file."

                        + e.getMessage());

            }

            actorType = properties.getProperty(type);

            if (actorType == null || actorType.equals("")) {

                System.out.println("Error loading actor type for type: " + type);

            }

     

            try {

                actorClass = Class.forName(actorType);

            } catch (ClassNotFoundException e) {

                System.out.println("Error: class " + actorType + " not found!");

                System.out.println(e.getMessage());

            } catch (Exception e) {

                e.printStackTrace();

                System.out.println(e.getMessage());

            }

     

            if (actorClass != null) {

                try {

                    actor = (Actor) actorClass.newInstance();

                } catch (Exception e) {

                    e.printStackTrace();

                    System.out.println(e.getMessage());

                }

            }

            return actor;

        }

    你當然可以添加屬性來指定添加多少的類型到simulator,這樣最好了。

    現在你可以不需要指定任何的actor具體類在你代碼的任何地方,你已經完全的解耦了。

     概要

    不同的工廠模式的目的是減少依賴具體的類。我們一步步進展并明白了如何移除最后的依賴。首先,我們將具體實例對象的代碼移到我們的主要代碼之外,將它放到一個工廠里。然后我們在這個基礎上改進它,再將路徑名和類名傳遞給工廠的基礎上,使它動態地裝入具體的類和實例化他們,這僅僅是必須確保每一個傳遞來得類都實現了工廠的返回接口。最后,我們打破了最后的依賴,從properties文件裝入我們想要的類型到simulator這使我們完全的消除了與具體類的依賴。

    記住,當你減少依賴的時候,你不需保證你的代碼的健壯性、可維護性、擴展性。

      

    完整的代碼

    如果你想試一下這個程序,你可以拷貝下面的代碼到一個文件,StampedeSimulatorTestDrive.java:

    package headfirst.factory.simulator;

    import java.io.FileInputStream;

    import java.io.IOException;

    import java.util.Properties;

     

    public class StampedeSimulatorTestDrive {

        public static void main(String[] args) {

            System.out.println("Stampede Test Drive");

            StampedeSimulator simulator = new StampedeSimulator();

            simulator.addActor("buffalo");

            simulator.addActor("horse");

            simulator.addActor("cowboy");

            simulator.addActor("cowgirl");

        }

    }

     

    class StampedeSimulator {

     

        public void addActor(String type) {

            Actor actor = null;

            actor = ActorFactory.createActor(type);

            actor.display();

            // rest of stampede simulator here

        }

    }

     

    class ActorFactory {

     

        static public Actor createActor(String type) {

            Class actorClass = null;

            Actor actor = null;

            String actorType = null;

            Properties properties = new Properties();

       try {

                properties.load(new FileInputStream("simulator.properties"));

            } catch (IOException e) {

                System.out.println("Error: couldn't read from the simulator.properties file."

                                    + e.getMessage());

            }

            actorType = properties.getProperty(type);

            if (actorType == null || actorType.equals("")) {

                System.out.println("Error loading actor type for type: " + type);

            }

     

            try {

                actorClass = Class.forName(actorType);

            } catch (ClassNotFoundException e) {

                System.out.println("Error: class " + actorType + " not found!");

                System.out.println(e.getMessage());

            } catch (Exception e) {

                e.printStackTrace();

                System.out.println(e.getMessage());

            }

     

            if (actorClass != null) {

                try {

                    actor = (Actor) actorClass.newInstance();

                } catch (Exception e) {

                    e.printStackTrace();

                    System.out.println(e.getMessage());

                }

            }

            return actor;

        }

    }

     

    interface Actor { 

        public void display();

    }

     

    class Buffalo implements Actor { 

        public void display() {

            System.out.println("I'm a Buffalo");

        }

    }

     

    class Horse implements Actor { 

        public void display() {

            System.out.println("I'm a Horse");

        }

    }

     

    class Cowboy implements Actor { 

        public void display() {

            System.out.println("I'm a Cowboy");

        }

    }

     

    class Cowgirl implements Actor { 

        public void display() {

            System.out.println("I'm a Cowgirl");

        }

    }

    確認保存這個文件到目錄src/headfirst/factory/simulator.如果你已經下載了Head First Design Patterns中的代碼code你就已經有了src/headfirst/factory目錄,只要新建一個simulator目錄在factory目錄就可以了創建一個class目錄保存你的class文件。

    確認保存這個文件到目錄src/headfirst/factory/simulator.如果你已經下載了Head First Design Patterns中的代碼code你就已經有了src/headfirst/factory目錄,只要新建一個simulator目錄在factory目錄就可以了創建一個class目錄保存你的class文件。

        不要忘了創建一個simulator.properties文件,包括你的屬性項(這個文件是最重要的):

     

    
    

    
    

    buffalo = headfirst.factory.simulator.Buffalo

    horse = headfirst.factory.simulator.Horse

    cowboy = headfirst.factory.simulator.Cowboy

    cowgirl = headfirst.factory.simulator.Cowgirl

    現在可以編譯、運行代碼象下面:

     

    javac -d ./classes ./src/headfirst/factory/simulator/StampedeSimulatorTestDrive.java

    java -cp ./classes headfirst.factory.simulator.StampedeSimulatorTestDrive

    你可以看到下面的輸出:

     

    Stampede Test Drive

    I'm a Buffalo

    I'm a Horse

    I'm a Cowboy

    I'm a Cowgirl
    posted on 2005-05-26 09:20 zming's blog 閱讀(2122) 評論(2)  編輯  收藏 所屬分類: Java Tech

    評論

    # re: 打破最后的依賴-Head First Design Patterns對工廠的解釋 2005-06-22 08:14 sniper
    請問你是從哪里找到Head First Design Patterns的 ?  回復  更多評論
      

    # re: 打破最后的依賴-Head First Design Patterns對工廠的解釋 2006-02-06 12:49 triper
    >記住,當你減少依賴的時候,你不需保證你的代碼的健壯性、可維護性、擴展性.

    Remember, when you reduce dependencies, you make your code more flexible and easier to maintain and extend.   回復  更多評論
      

    主站蜘蛛池模板: 成人国产网站v片免费观看| 成人亚洲国产精品久久| 亚洲综合久久精品无码色欲 | 国产午夜亚洲精品国产成人小说| 亚洲伊人久久综合中文成人网| 精品亚洲综合久久中文字幕| 91在线亚洲精品专区| 亚洲精品无码永久在线观看男男 | 99热在线精品免费全部my| 国产成人免费片在线观看| 美腿丝袜亚洲综合| 久久综合亚洲色HEZYO社区| 亚洲中文无码亚洲人成影院| 特级毛片免费观看视频| 免费福利电影在线观看| 国产卡一卡二卡三免费入口| 国产无遮挡裸体免费视频| 亚洲国产精品一区二区久久hs| 亚洲无人区视频大全| 色婷婷精品免费视频| 日本视频在线观看永久免费 | 99精品在线免费观看| 四虎www免费人成| 中文字幕精品亚洲无线码一区| 91嫩草亚洲精品| 免费一区二区无码视频在线播放 | 男女免费观看在线爽爽爽视频| 免费日本黄色网址| 内射少妇36P亚洲区| 久久亚洲中文字幕无码| 欧洲人成在线免费| 国产精品久久免费视频| 亚洲精品视频在线观看视频| 日本亚洲高清乱码中文在线观看| 国产精品免费看久久久| 国产高清免费在线| 亚洲综合图片小说区热久久| 理论片在线观看免费| 中文字幕乱码免费视频| 国产成人综合亚洲AV第一页| 亚洲日日做天天做日日谢|