設計模式之Factory

設計模式之 Factory
工廠模式定義:提供建立對象的接口.
爲什麼使用?
工廠模式是咱們最經常使用的模式了,著名的 Jive 論壇 ,就大量使用了工廠模式,工廠模式在
Java 程序系統能夠說是隨處可見。
爲何工廠模式是如此經常使用?由於工廠模式就至關於建立實例對象的 new,咱們常常要根據
類 Class 生成實例對象,如 A a=new A() 工廠模式也是用來建立實例對象的,因此之後
new 時就要多個心眼,是否能夠考慮實用工廠模式,雖然這樣作,可能多作一些工做,但會
給你係統帶來更大的可擴展性和儘可能少的修改量。
咱們以類 Sample 爲例, 若是咱們要建立 Sample 的實例對象:
Sample sample=new Sample();
但是,實際狀況是,一般咱們都要在建立 sample 實例時作點初始化的工做,好比賦值 查
詢數據庫等。
首先,咱們想到的是,可使用 Sample 的構造函數,這樣生成實例就寫成:
Sample sample=new Sample(參數);
可是,若是建立 sample 實例時所作的初始化工做不是象賦值這樣簡單的事,多是很長
一段代碼,若是也寫入構造函數中,那你的代碼很難看了(就須要 Refactor 重整)。
爲何說代碼很難看,初學者可能沒有這種感受,咱們分析以下,初始化工做若是是很長一
段代碼,說明要作的工做不少,將不少工做裝入一個方法中,至關於將不少雞蛋放在一個籃
子裏,是很危險的,這也是有背於Java 面向對象的原則,面向對象的封裝(Encapsulation)
和分派(Delegation)告訴咱們,儘可能將長的代碼分派「切割」成每段,將每段再「封裝」起
來(減小段和段之間偶合聯繫性),這樣,就會將風險分散,之後若是須要修改,只要更改
每段,不會再發生牽一動百的事情。
在本例中,首先,咱們須要將建立實例的工做與使用實例的工做分開, 也就是說,讓建立
實例所須要的大量初始化工做從 Sample 的構造函數中分離出去。
這時咱們就須要 Factory 工廠模式來生成對象了,不能再用上面簡單 new Sample(參數)。
還有,若是 Sample 有個繼承如 MySample, 按照面向接口編程,咱們須要將 Sample 抽象
成一個接口.如今 Sample 是接口,有兩個子類 MySample 和 HisSample .咱們要實例化
他們時,以下:
Sample mysample=new MySample();
Sample hissample=new HisSample();
隨着項目的深刻,Sample 可能還會"生出不少兒子出來", 那麼咱們要對這些兒子一個個
實例化,更糟糕的是,可能還要對之前的代碼進行修改:加入後來生出兒子的實例.這在傳統
程序中是沒法避免的.
但若是你一開始就有意識使用了工廠模式,這些麻煩就沒有了.
工廠方法
你會創建一個專門生產 Sample 實例的工廠:
public class Factory{
public static Sample creator(int which){
//getClass 產生 Sample 通常可以使用動態類裝載裝入類。
if (which==1)
return new SampleA();
else if (which==2)
return new SampleB();
}
}
那麼在你的程序中,若是要實例化 Sample 時.就使用
Sample sampleA=Factory.creator(1);
這樣,在整個就不涉及到 Sample 的具體子類,達到封裝效果,也就減小錯誤修改的機會,這
個原理能夠用很通俗的話來比喻:就是具體事情作得越多,越容易範錯誤.這每一個作過具體
工做的人都深有體會,相反,官作得越高,說出的話越抽象越籠統,範錯誤可能性就越少.好
象咱們從編程序中也能悟出人生道理?呵呵.
使用工廠方法 要注意幾個角色,首先你要定義產品接口,如上面的 Sample,產品接口下有
Sample 接口的實現類,如 SampleA,其次要有一個 factory 類,用來生成產品 Sample,
以下圖,最右邊是生產的對象 Sample:
進一步稍微複雜一點,就是在工廠類上進行拓展,工廠類也有繼承它的實現類
concreteFactory 了
抽象工廠
工廠模式中有: 工廠方法(Factory Method) 抽象工廠(Abstract Factory).
這兩個模式區別在於須要建立對象的複雜程度上。若是咱們建立對象的方法變得複雜了,如
上面工廠方法中是建立一個對象 Sample,若是咱們還有新的產品接口 Sample2.
這裏假設:Sample 有兩個 concrete 類 SampleA 和 SamleB,而 Sample2 也有兩個
concrete 類 Sample2A 和 SampleB2
那麼,咱們就將上例中 Factory 變成抽象類,將共同部分封裝在抽象類中,不一樣部分使用子
類實現,下面就是將上例中的 Factory 拓展成抽象工廠:public abstract class Factory{public abstract Sample creator();public abstract Sample2 creator(Stringname);}public class SimpleFactory extends Factory{public Sample creator(){.........return new SampleA}public Sample2 creator(String name){.........return new Sample2A}}public class BombFactory extends Factory{public Sample creator(){......return new SampleB}public Sample2 creator(String name){......return new Sample2B}}
從上面看到兩個工廠各自生產出一套 Sample 和 Sample2,也許你會疑問,爲何我不可
以使用兩個工廠方法來分別生產 Sample 和 Sample2?
抽象工廠還有另一個關鍵要點,是由於 SimpleFactory 內,生產 Sample 和生產
Sample2 的方法之間有必定聯繫,因此纔要將這兩個方法捆綁在一個類中,這個工廠類有
其自己特徵,也許製造過程是統一的,好比:製造工藝比較簡單,因此名稱叫
SimpleFactory。
在實際應用中,工廠方法用得比較多一些,並且是和動態類裝入器組合在一塊兒應用,
舉例<?XML:NAMESPACE PREFIX = O /><O:P></O:P>
咱們以 Jive 的 ForumFactory 爲例,這個例子在前面的 Singleton 模式中咱們討論過,
如今再討論其工廠模式:
public abstract class ForumFactory {
private static Object initLock = new Object();
private static String className =
"com.jivesoftware.forum.database.DbForumFactory";
private static ForumFactory factory = null;
public static ForumFactory getInstance(Authorization
authorization) {
//If no valid authorization passed in, return null.
if (authorization == null) {
return null;
}
//如下使用了 Singleton 單態模式
if (factory == null) {
synchronized(initLock) {
if (factory == null) {
......
try {
//動態轉載類
Class c = Class.forName(className);
factory = (ForumFactory)c.newInstance();
}
catch (Exception e) {
return null;
}
}
}
}
//Now, 返回 proxy.用來限制受權對 forum 的訪問
return new ForumFactoryProxy(authorization, factory,

factory.getPermissions(authorization));
}
//真正建立 forum 的方法由繼承 forumfactory 的子類去完成.
public abstract Forum createForum(String name, String
description)
throws UnauthorizedException, ForumAlreadyExistsException;
....
}
由於如今的 Jive 是經過數據庫系統存放論壇帖子等內容數據,若是但願更改成經過文件系
統實現,這個工廠方法 ForumFactory 就提供了提供動態接口:
private static String className =
"com.jivesoftware.forum.database.DbForumFactory";
你可使用本身開發的建立 forum 的方法代替
com.jivesoftware.forum.database.DbForumFactory 就能夠.
在上面的一段代碼中一共用了三種模式,除了工廠模式外,還有 Singleton 單態模式,以及
proxy 模式,proxy 模式主要用來受權用戶對 forum 的訪問,由於訪問 forum 有兩種人:
一個是註冊用戶 一個是遊客 guest,那麼那麼相應的權限就不同,並且這個權限是貫穿
整個系統的,所以創建一個 proxy,相似網關的概念,能夠很好的達到這個效果.
看看 Java 寵物店中的 CatalogDAOFactory:
public class CatalogDAOFactory {
/**
* 本方法制定一個特別的子類來實現 DAO 模式。
* 具體子類定義是在 J2EE 的部署描述器中。
*/
public static CatalogDAO getDAO() throws CatalogDAOSysException
{
CatalogDAO catDao = null;
try {
InitialContext ic = new InitialContext();
//動態裝入 CATALOG_DAO_CLASS
//能夠定義本身的 CATALOG_DAO_CLASS,從而在無需變動太多代碼
//的前提下,完成系統的巨大變動。
String className =(String)
ic.lookup(JNDINames.CATALOG_DAO_CLASS);
catDao = (CatalogDAO)
Class.forName(className).newInstance();
} catch (NamingException ne) {
throw new CatalogDAOSysException("
CatalogDAOFactory.getDAO: NamingException while
getting DAO type : \n" + ne.getMessage());
} catch (Exception se) {
throw new CatalogDAOSysException("
CatalogDAOFactory.getDAO: Exception while getting
DAO type : \n" + se.getMessage());
}
return catDao;
}
}
CatalogDAOFactory 是典型的工廠方法,catDao 是經過動態類裝入器 className 獲
得 CatalogDAOFactory 具體實現子類,這個實現子類在 Java 寵物店是用來操做
catalog 數據庫,用戶能夠根據數據庫的類型不一樣,定製本身的具體實現子類,將本身的
子類名給與 CATALOG_DAO_CLASS 變量就能夠。
因而可知,工廠方法確實爲系統結構提供了很是靈活強大的動態擴展機制,只要咱們更換一
下具體的工廠方法,系統其餘地方無需一點變換,就有可能將系統功能進行改頭換面的變化。

數據庫

相關文章
相關標籤/搜索