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

Liuwei-Sunny發表於2013-07-12

       簡單工廠模式雖然簡單,但存在一個很嚴重的問題。當系統中需要引入新產品時,由於靜態工廠方法通過所傳入引數的不同來建立不同的產品,這必定要修改工廠類的原始碼,將違背“開閉原則”,如何實現增加新產品而不影響已有程式碼?工廠方法模式應運而生,本文將介紹第二種工廠模式——工廠方法模式。

 

1 日誌記錄器的設計

       Sunny軟體公司欲開發一個系統執行日誌記錄器(Logger),該記錄器可以通過多種途徑儲存系統的執行日誌,如通過檔案記錄或資料庫記錄,使用者可以通過修改配置檔案靈活地更換日誌記錄方式。在設計各類日誌記錄器時,Sunny公司的開發人員發現需要對日誌記錄器進行一些初始化工作,初始化引數的設定過程較為複雜,而且某些引數的設定有嚴格的先後次序,否則可能會發生記錄失敗。如何封裝記錄器的初始化過程並保證多種記錄器切換的靈活性是Sunny公司開發人員面臨的一個難題。

       Sunny公司的開發人員通過對該需求進行分析,發現該日誌記錄器有兩個設計要點:

       (1) 需要封裝日誌記錄器的初始化過程,這些初始化工作較為複雜,例如需要初始化其他相關的類,還有可能需要讀取配置檔案(例如連線資料庫或建立檔案),導致程式碼較長,如果將它們都寫在建構函式中,會導致建構函式龐大,不利於程式碼的修改和維護;

       (2) 使用者可能需要更換日誌記錄方式,在客戶端程式碼中需要提供一種靈活的方式來選擇日誌記錄器,儘量在不修改原始碼的基礎上更換或者增加日誌記錄方式。

       Sunny公司開發人員最初使用簡單工廠模式對日誌記錄器進行了設計,初始結構如圖1所示:

 

1 基於簡單工廠模式設計的日誌記錄器結構圖

       在圖1中,LoggerFactory充當建立日誌記錄器的工廠,提供了工廠方法createLogger()用於建立日誌記錄器,Logger是抽象日誌記錄器介面,其子類為具體日誌記錄器。其中,工廠類LoggerFactory程式碼片段如下所示:

//日誌記錄器工廠
class LoggerFactory {
    //靜態工廠方法
	public static Logger createLogger(String args) {
		if(args.equalsIgnoreCase("db")) {
			//連線資料庫,程式碼省略
			//建立資料庫日誌記錄器物件
			Logger logger = new DatabaseLogger(); 
			//初始化資料庫日誌記錄器,程式碼省略
			return logger;
		}
		else if(args.equalsIgnoreCase("file")) {
			//建立日誌檔案
			//建立檔案日誌記錄器物件
			Logger logger = new FileLogger(); 
			//初始化檔案日誌記錄器,程式碼省略
			return logger;			
		}
		else {
			return null;
		}
	}
}


       為了突出設計重點,我們對上述程式碼進行了簡化,省略了具體日誌記錄器類的初始化程式碼。在LoggerFactory類中提供了靜態工廠方法createLogger(),用於根據所傳入的引數建立各種不同型別的日誌記錄器。通過使用簡單工廠模式,我們將日誌記錄器物件的建立和使用分離,客戶端只需使用由工廠類建立的日誌記錄器物件即可,無須關心物件的建立過程,但是我們發現,雖然簡單工廠模式實現了物件的建立和使用分離,但是仍然存在如下兩個問題:

       (1) 工廠類過於龐大,包含了大量的if…else…程式碼,導致維護和測試難度增大;

       (2) 系統擴充套件不靈活,如果增加新型別的日誌記錄器,必須修改靜態工廠方法的業務邏輯,違反了“開閉原則”。

       如何解決這兩個問題,提供一種簡單工廠模式的改進方案?這就是本文所介紹的工廠方法模式的動機之一。

 

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

相關文章