<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 工廠三兄弟之工廠方法模式(三) 3 完整解決方案 Sunny公司開發人員決定使用工廠方法模式來設計日志記錄器,其基本結構如圖3所示: ![日志記錄器結構圖](http://img.blog.csdn.net/20130712102729562?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTG92ZUxpb24=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 圖3 日志記錄器結構圖 在圖3中,Logger接口充當抽象產品,其子類FileLogger和DatabaseLogger充當具體產品,LoggerFactory接口充當抽象工廠,其子類FileLoggerFactory和DatabaseLoggerFactory充當具體工廠。完整代碼如下所示: ``` //日志記錄器接口:抽象產品 interface Logger { public void writeLog(); } //數據庫日志記錄器:具體產品 class DatabaseLogger implements Logger { public void writeLog() { System.out.println("數據庫日志記錄。"); } } //文件日志記錄器:具體產品 class FileLogger implements Logger { public void writeLog() { System.out.println("文件日志記錄。"); } } //日志記錄器工廠接口:抽象工廠 interface LoggerFactory { public Logger createLogger(); } //數據庫日志記錄器工廠類:具體工廠 class DatabaseLoggerFactory implements LoggerFactory { public Logger createLogger() { //連接數據庫,代碼省略 //創建數據庫日志記錄器對象 Logger logger = new DatabaseLogger(); //初始化數據庫日志記錄器,代碼省略 return logger; } } //文件日志記錄器工廠類:具體工廠 class FileLoggerFactory implements LoggerFactory { public Logger createLogger() { //創建文件日志記錄器對象 Logger logger = new FileLogger(); //創建文件,代碼省略 return logger; } } ``` 編寫如下客戶端測試代碼: ``` class Client { public static void main(String args[]) { LoggerFactory factory; Logger logger; factory = new FileLoggerFactory(); //可引入配置文件實現 logger = factory.createLogger(); logger.writeLog(); } } ``` 編譯并運行程序,輸出結果如下: 文件日志記錄。 4 反射與配置文件 為了讓系統具有更好的靈活性和可擴展性,Sunny公司開發人員決定對日志記錄器客戶端代碼進行重構,使得可以在不修改任何客戶端代碼的基礎上更換或增加新的日志記錄方式。 在客戶端代碼中將不再使用new關鍵字來創建工廠對象,而是將具體工廠類的類名存儲在配置文件(如XML文件)中,通過讀取配置文件獲取類名字符串,再使用Java的反射機制,根據類名字符串生成對象。在整個實現過程中需要用到兩個技術:Java反射機制與配置文件讀取。軟件系統的配置文件通常為XML文件,我們可以使用DOM (Document Object Model)、SAX (Simple API for XML)、StAX (Streaming API for XML)等技術來處理XML文件。關于DOM、SAX、StAX等技術的詳細學習大家可以參考其他相關資料,在此不予擴展。 擴展 關于Java與XML的相關資料,大家可以閱讀Tom Myers和Alexander Nakhimovsky所著的《Java XML編程指南》一書或訪問developer Works 中國中的“Java XML 技術專題”,參考鏈接: http://www.ibm.com/developerworks/cn/xml/theme/x-java.html Java反射(Java Reflection)是指在程序運行時獲取已知名稱的類或已有對象的相關信息的一種機制,包括類的方法、屬性、父類等信息,還包括實例的創建和實例類型的判斷等。在反射中使用最多的類是Class,Class類的實例表示正在運行的Java應用程序中的類和接口,其forName(String className)方法可以返回與帶有給定字符串名的類或接口相關聯的 Class對象,再通過Class對象的newInstance()方法創建此對象所表示的類的一個新實例,即通過一個類名字符串得到類的實例。如創建一個字符串類型的對象,其代碼如下: ``` //通過類名生成實例對象并將其返回 Class c=Class.forName("String"); Object obj=c.newInstance(); return obj; ``` 此外,在JDK中還提供了java.lang.reflect包,封裝了其他與反射相關的類,此處只用到上述簡單的反射代碼,在此不予擴展。 Sunny公司開發人員創建了如下XML格式的配置文件config.xml用于存儲具體日志記錄器工廠類類名: ``` <!— config.xml --> <?xml version="1.0"?> <config> <className>FileLoggerFactory</className> </config> ``` 為了讀取該配置文件并通過存儲在其中的類名字符串反射生成對象,Sunny公司開發人員開發了一個名為XMLUtil的工具類,其詳細代碼如下所示: ``` //工具類XMLUtil.java import javax.xml.parsers.*; import org.w3c.dom.*; import org.xml.sax.SAXException; import java.io.*; public class XMLUtil { //該方法用于從XML配置文件中提取具體類類名,并返回一個實例對象 public static Object getBean() { try { //創建DOM文檔對象 DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = dFactory.newDocumentBuilder(); Document doc; doc = builder.parse(new File("config.xml")); //獲取包含類名的文本節點 NodeList nl = doc.getElementsByTagName("className"); Node classNode=nl.item(0).getFirstChild(); String cName=classNode.getNodeValue(); //通過類名生成實例對象并將其返回 Class c=Class.forName(cName); Object obj=c.newInstance(); return obj; } catch(Exception e) { e.printStackTrace(); return null; } } } ``` 有了XMLUtil類后,可以對日志記錄器的客戶端代碼進行修改,不再直接使用new關鍵字來創建具體的工廠類,而是將具體工廠類的類名存儲在XML文件中,再通過XMLUtil類的靜態工廠方法getBean()方法進行對象的實例化,代碼修改如下: ``` class Client { public static void main(String args[]) { LoggerFactory factory; Logger logger; factory = (LoggerFactory)XMLUtil.getBean(); //getBean()的返回類型為Object,需要進行強制類型轉換 logger = factory.createLogger(); logger.writeLog(); } } ``` 引入XMLUtil類和XML配置文件后,如果要增加新的日志記錄方式,只需要執行如下幾個步驟: (1) 新的日志記錄器需要繼承抽象日志記錄器Logger; (2) 對應增加一個新的具體日志記錄器工廠,繼承抽象日志記錄器工廠LoggerFactory,并實現其中的工廠方法createLogger(),設置好初始化參數和環境變量,返回具體日志記錄器對象; (3) 修改配置文件config.xml,將新增的具體日志記錄器工廠類的類名字符串替換原有工廠類類名字符串; (4) 編譯新增的具體日志記錄器類和具體日志記錄器工廠類,運行客戶端測試類即可使用新的日志記錄方式,而原有類庫代碼無須做任何修改,完全符合“開閉原則”。 通過上述重構可以使得系統更加靈活,由于很多設計模式都關注系統的可擴展性和靈活性,因此都定義了抽象層,在抽象層中聲明業務方法,而將業務方法的實現放在實現層中。 疑問 思考 有人說:可以在客戶端代碼中直接通過反射機制來生成產品對象,在定義產品對象時使用抽象類型,同樣可以確保系統的靈活性和可擴展性,增加新的具體產品類無須修改源代碼,只需要將其作為抽象產品類的子類再修改配置文件即可,根本不需要抽象工廠類和具體工廠類。 試思考這種做法的可行性?如果可行,這種做法是否存在問題?為什么?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看