定義1個用于創建對象的接口,讓子類決定實例化哪個類。FactoryMethod使1個類的實例化延遲到其子類。
1.當1個類不知道它所必須創建的對象的類的時候。 2.當1個類希望由它的子類來指定它所創建的對象的時候。 3.當類將創建對象的職責拜托給多個幫助子類中的某1個,并且你希望將哪個幫助子類是代理者這1信息局部化的時候。
1.Product 定義工廠方法所創建的對象的接口。 2.ConcreteProduct 實現Product接口。 3.Creator 聲明工廠方法,該方法返回1個Product類型的對象。 Creator也能夠定義1個工廠方法的缺省實現,它返回1個缺省的ConcreteProduct對象。 可以調用工廠方法以創建1個Product對象。 4.ConcreteCreator 重定義工廠方法以返回1個ConcreteProduct實例。
public interface Work { void doWork(); }
public class StudentWork implements Work { public void doWork() { System.out.println("學生寫作業!"); } }
public class TeacherWork implements Work { public void doWork() { System.out.println("老師批作業!"); } }
public interface IWorkFactory { Work getWork(); }
public class StudentWorkFactory implements IWorkFactory { public Work getWork() { return new StudentWork(); } }
public class TeacherWorkFactory implements IWorkFactory { public Work getWork() { return new TeacherWork(); } }
public class Test { public static void main(String[] args) { IWorkFactory studentWorkFactory = new StudentWorkFactory(); studentWorkFactory.getWork().doWork(); IWorkFactory teacherWorkFactory = new TeacherWorkFactory(); teacherWorkFactory.getWork().doWork(); } }
學生寫作業! 老師批作業!
工廠模式定義:提供創建對象的接口。為什么使用工廠模式
工廠模式是我們最經常使用的模式了,著名的Jive論壇,就大量使用了工廠模式,工廠模式在Java程序系統可以說是隨處可見。
為何工廠模式是如此經常使用?由于工廠模式就相當于創建實例對象的new,我們常常要根據類Class生成實例對象,如A a=new A() 工廠模式也是用來創建實例對象的,所以以后new時就要多個心眼,是不是可以斟酌實用工廠模式,雖然這樣做,可能多做1些工作,但會給你系統帶來更大的可擴大性和盡可能少的修改量。
我們以類Sample為例, 如果我們要創建Sample的實例對象:
Sample sample=new Sample();
可是,實際情況是,通常我們都要在創建sample實例時做點初始化的工作,比如賦值查詢數據庫等。
首先,我們想到的是,可使用Sample的構造函數,這樣生成實例就寫成:
Sample sample=new Sample(參數);
但是,如果創建sample實例時所做的初始化工作不是象賦值這樣簡單的事,多是很長1段代碼,如果也寫入構造函數中,那你的代碼很難看了(就需要Refactor重整)。
為何說代碼很難看,初學者可能沒有這類感覺,我們分析以下,初始化工作如果是很長1段代碼,說明要做的工作很多,將很多工作裝入1個方法中,相當于將很多雞蛋放在1個籃子里,是很危險的,這也是有背于Java面向對象的原則,面向對象的封裝(Encapsulation)和分派(Delegation)告知我們,盡可能將長的代碼分派“切割”成每段,將每段再“封裝”起來(減少段和段之間偶合聯系性),這樣,就會將風險分散,以后如果需要修改,只要更改每段,不會再產生牽1動百的事情。
在本例中,首先,我們需要將創建實例的工作與使用實例的工作分開,也就是說,讓創建實例所需要的大量初始化工作從Sample的構造函數中分離出去。
這時候我們就需要Factory工廠模式來生成對象了,不能再用上面簡單new Sample(參數)。還有,如果Sample有個繼承如MySample,依照面向接口編程,我們需要將Sample抽象成1個接口?,F在Sample是接口,有兩個子類MySample 和HisSample。我們要實例化他們時,以下:
Sample mysample=new MySample(); Sample hissample=new HisSample();
隨著項目的深入,Sample可能還會"生出很多兒子出來",那末我們要對這些兒子1個個實例化,更糟的是,可能還要對之前的代碼進行修改:加入后來生出兒子的實例.這在傳統程序中是沒法避免的。
但如果你1開始就成心識使用了工廠模式,這些麻煩就沒有了。工廠方法
你會建立1個專門生產Sample實例的工廠:public class Factory{ public static Sample creator(int which){ //getClass 產生Sample 1般可以使用動態類裝載裝入類。 if (which==1) return new SampleA(); else if (which==2) return new SampleB(); } }那末在你的程序中,如果要實例化Sample時就使用
Sample sampleA=Factory.creator(1);
這樣,在全部就不觸及到Sample的具體子類,到達封裝效果,也就減少毛病修改的機會,這個原理可以用很通俗的話來比喻:就是具體事情做得越多,越容易范毛病。這每一個做過具體工作的人都深有體會,相反,官做得越高,說出的話越抽象越笼統,范毛病可能性就越少。好象我們從編程序中也能悟出人生道理?
使用工廠方法要注意幾個角色,首先你要定義產品接口,如上面的Sample,產品接口下有Sample接口的實現類,如SampleA,其次要有1個factory類,用來生成產品Sample,以下圖,最右側是生產的對象Sample:
進1步略微復雜1點,就是在工廠類上進行拓展,工廠類也有繼承它的實現類concreteFactory了。抽象工廠
工廠模式中有:工廠方法(Factory Method)和抽象工廠(Abstract Factory)。
這兩個模式區分在于需要創建對象的復雜程度上。如果我們創建對象的方法變得復雜了,如上面工廠方法中是創建1個對象Sample,如果我們還有新的產品接口Sample2。
這里假定:Sample有兩個concrete類SampleA和SamleB,而Sample2也有兩個concrete類Sample2A和SampleB2,那末,我們就將上例中Factory變成抽象類,將共同部份封裝在抽象類中,不同部份使用子類實現,下面就是將上例中的Factory拓展成抽象工廠:public abstract class Factory{ public abstract Sample creator(); public abstract Sample2 creator(String name); } 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 } }從上面看到兩個工廠各自生產出1套Sample和Sample2,或許你會疑問,為何我不可使用兩個工廠方法來分別生產Sample和Sample2?
抽象工廠還有另外1個關鍵要點,是由于 SimpleFactory內,生產Sample和生產Sample2的方法之間有1定聯系,所以才要將這兩個方法捆綁在1個類中,這個工廠類有其本身特點,或許制造進程是統1的,比如:制造工藝比較簡單,所以名稱叫SimpleFactory。
在實際利用中,工廠方法用得比較多1些,而且是和動態類裝入器組合在1起利用,Java工廠模式舉例
我們以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就能夠。
在上面的1段代碼中1共用了3種模式,除工廠模式外,還有Singleton單態模式,和proxy模式,proxy模式主要用來授權用戶對forum的訪問,由于訪問forum有兩種人:1個是注冊用戶1個是游客guest,那末那末相應的權限就不1樣,而且這個權限是貫穿全部系統的,因此建立1個proxy,類似網關的概念,可以很好的到達這個效果。
看看Java寵物店中的CatalogDAOFactory:public class CatalogDAOFactory { /** * 本方法制定1個特別的子類來實現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 : " + ne.getMessage()); } catch (Exception se) { throw new CatalogDAOSysException("CatalogDAOFactory.getDAO: Exception while getting DAO type : " + se.getMessage()); } return catDao; } }CatalogDAOFactory是典型的工廠方法,catDao是通過動態類裝入器className取得CatalogDAOFactory具體實現子類,這個實現子類在Java寵物店是用來操作catalog數據庫,用戶可以根據數據庫的類型不同,定制自己的具體實現子類,將自己的子類名給與CATALOG_DAO_CLASS變量就能夠。
因而可知,工廠方法確切為系統結構提供了非常靈活強大的動態擴大機制,只要我們更換1下具體的工廠方法,系統其他地方無需1點變換,就有可能將系統功能進行改頭換面的變化。
上一篇 電腦文件加密
下一篇 RecentApps圖標異常分析