1. 程式人生 > >工廠三兄弟之工廠方法模式(三)

工廠三兄弟之工廠方法模式(三)

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

3 完整解決方案

        Sunny公司開發人員決定使用工廠方法模式來設計日誌記錄器,其基本結構如圖3所示:

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檔案。關於DOMSAXStAX等技術的詳細學習大家可以參考其他相關資料,在此不予擴充套件。

微笑

擴充套件

關於JavaXML的相關資料,大家可以閱讀Tom MyersAlexander Nakhimovsky所著的《Java XML程式設計指南》一書或訪問developer Works 中國中的“Java XML 技術專題”,參考連結:

http://www.ibm.com/developerworks/cn/xml/theme/x-java.html

       Java反射(Java Reflection)是指在程式執行時獲取已知名稱的類或已有物件的相關資訊的一種機制,包括類的方法、屬性、父類等資訊,還包括例項的建立和例項型別的判斷等。在反射中使用最多的類是ClassClass類的例項表示正在執行的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.javaimport 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) 編譯新增的具體日誌記錄器類和具體日誌記錄器工廠類,執行客戶端測試類即可使用新的日誌記錄方式,而原有類庫程式碼無須做任何修改,完全符合“開閉原則”。

      通過上述重構可以使得系統更加靈活,由於很多設計模式都關注系統的可擴充套件性和靈活性,因此都定義了抽象層,在抽象層中宣告業務方法,而將業務方法的實現放在實現層中。

疑問

思考

       有人說:可以在客戶端程式碼中直接通過反射機制來生成產品物件,在定義產品物件時使用抽象型別,同樣可以確保系統的靈活性和可擴充套件性,增加新的具體產品類無須修改原始碼,只需要將其作為抽象產品類的子類再修改配置檔案即可,根本不需要抽象工廠類和具體工廠類。

       試思考這種做法的可行性?如果可行,這種做法是否存在問題?為什麼?



【作者:劉偉 http://blog.csdn.net/lovelion

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述