版權聲明:尊重部落客原創文章,轉載請注明出處哦~http://blog.csdn.net/eson_15/article/details/51223124
工廠模式使用的頻率非常高,我們在開發中總能見到它們的身影。其定義為:define an interface for creating an object, but let subclasses decide which class to instantiate. factory method lets a class defer instantiation to subclasses.即定義一個用于建立對象的接口,讓子類決定執行個體化哪一個類。工廠方法使一個類的執行個體化延遲到其子類。工廠方法模式的通用類圖如下所示:

如圖所示,product抽象類負責定義産品的共性,實作對事物最抽象的定義,creator為抽象工廠類,具體如何建立産品類由具體的實作工廠concretecreator來完成。我們來看一下通用的模闆代碼:
public abstract class product {
public void method() { //産品類的公共方法,已經實作
//實作了公共的邏輯
}
public abstract void method2(); //非公共方法,需要子類具體實作
}
具體産品類可以有多個,都繼承與抽象類product,如下:
public class concreateproduct1 extends product {
@override
public void method2() {
//product1的業務邏輯
public class concreateproduct2 extends product {
//product2的業務邏輯
抽象工廠類負責定義産品對象的産生,代碼如下:
public abstract class creator {
//建立一個産品對象,其輸入參數類型可以自行設定
public abstract <t extends product> t createproduct(class<t> clazz);
這裡用的是泛型,傳入的對象必須是product抽象類的實作類。具體如何産生一個産品的對象,是由具體工廠類實作的,具體工廠類繼承這個抽象工廠類:
public class concretecreator extends creator {
public <t extends product> t createproduct(class<t> clazz) {
product product = null;
try {
product = (product) class.forname(clazz.getname()).newinstance();
} catch (exception e) { //異常處理
e.printstacktrace();
}
return (t) product;
通過這樣的設計,我們就可以在測試類中随意生産産品了,看下面的測試類:
public class factorytest {
public static void main(string[] args) {
creator factory = new concretecreator();
product product1 = factory.createproduct(concreteproduct1.class); //通過不同的類建立不同的産品
product product2 = factory.createproduct(concreteproduct2.class);
/*
* 下面繼續其他業務處理
*/
}
下面舉個女娲造人的例子闡述一下工廠模式的實際應用。
現在女娲要造人,她要造三種人:白種人、黃種人和黑種人。怎麼造呢?她得有個能産生人類的工廠吧(類似于八卦爐的東西),這個工廠得讓她生産出不同的人種。每個人都有兩個屬性:皮膚顔色和說話。那現在我們開始設計女蝸造人的程式,首先我們看一下造人的類圖:
抽象接口human是人類,裡面有兩個方法,getcolor獲得皮膚顔色,talk交談。下面三個具體human的實作類,分别實作三個人種。根據工廠模式,應該有個抽象工廠,abstracthumanfactory就擔當了這個責任,裡面有個抽象方法createhuman,那humanfactory就是實作類了,實作抽象工廠裡的方法。下面我們看看具體實作:
public interface human {
public void getcolor();//人有不同的顔色
public void talk(); //人會說話
接下來對human接口的不同實作:
public class blackhuman implements human {// 黑種人
public void getcolor() {
system.out.println("black");
public void talk() {
system.out.println("black man");
public class human implements human { //黃種人
system.out.println("yellow");
system.out.println("yellow man");
public class whitehuman implements human {//白種人
system.out.println("white");
system.out.println("white man");
好了,人的模子搞好了,現在女娲要開始搭建八卦爐了,于是女娲開始畫八卦爐模型了:
public abstract class abstracthumanfactory{
public abstract <t extends human> t createhuman(class<t> clazz); //注意這裡t必須是human的實作類才行,因為要造human嘛
然後女娲開始具體實作這個八卦爐了……
public class humanfactory extends abstracthumanfactory {
public <t extends human> t createhuman(class<t> clazz) {
human human = null;
human = (product) class.forname(clazz.getname()).newinstance();
system.out.println("人種産生錯誤");
return (t) human;
好,現在人種也有了,八卦爐也有了,剩下的就是采集黃土,然後指令八卦爐開始生産了:
abstracthumanfactory bagualu = new hunmanfactory();
human blackman = bagualu.createhuman(blackhuman.class); //黑人誕生了
human yellowman = bagualu.createhuman(yellohuman.class); //黃人誕生了
human whiteman = bagualu.createhuman(whitehuman.class); //白人誕生了
}
女娲就是這麼把人造出來的……這就是工廠模式!
我們還用上面女娲造人的例子說明,現在女娲在思考一個問題:我現在隻需要一個工廠就可以把人生産出來,我幹嘛要具體的工廠對象呢?我隻要使用靜态方法就好了。這樣一想,于是女娲就開始把abstracthumanfactory抽象類去掉了,隻保留了humanfactory類,同時把createhuman方法設定成了static類型,搞定!
public class humanfactory {
public static <t extends human> t createhuman(class<t> clazz) {
然後女娲造人的時候就不用new什麼八卦爐了,直接用humanfactory類調用就行了:
human blackman = humanfactory.createhuman(blackhuman.class);
這就是靜态工廠模式,在實際項目中,根據需求可以設定成靜态工廠類,但是缺點是擴充比較困難,如果就一個工廠,不需要擴充,可以這麼設計,仍然是很常用的。
我們還以女娲造人為例,後來女娲想了想,,這人不可能就說話吧,還得有不同的屬性殺的,如果在一個八卦爐裡造,除了new一個人外,還得對不同的人設定不同的屬性,這樣的話,八卦爐有點吃不消阿……又有點亂啊……但是她想到了一個法子,每個人種弄個八卦爐,不同的八卦爐專門生産不同的人種,這樣就結構清晰了,她在造人的時候自己選擇與哪個八卦爐相關聯就行了。示意圖如下:
這樣的話abstracthumanfactory抽象類我們就要改寫了:
public abstract class abstracthumanfactory {
public abstract human createhuman();
注意抽象方法中已經不需要再傳遞相關類的參數了,因為每個具體的工廠都已經非常明确自己的職責:建立自己負責的産品類對象。是以不同的工廠實作自己的createhuman方法即可:
public class blackhumanfactory extends abstracthumanfactory {
public human createhuman() {
return new blackhuman();
public class yellowhumanfactory extends abstracthumanfactory {
return new yellowhuman();
public class whitehumanfactory extends abstracthumanfactory {
return new whitehuman();
這樣三個不同的工廠就産生了,每個工廠對應隻生産自己對應的人種。是以現在女娲造人就可以不用一個八卦爐了,分工協作,各不影響了!
human blackman = new blackhumanfactory().createhuman(); //黑人誕生了
human yellowman = new yellowhumanfactory().createhuman(); //黃人誕生了
human whiteman = new whitehumanfactory().createhuman(); //白人誕生了
這種工廠模式的好處是職責清晰,結構簡單,但是給擴擴充性和可維護性帶來了一定的影響,因為如果要擴充一個産品類,就需要建立一個相應的工廠類,這樣就增加了擴充的難度。因為工廠類和産品類的數量是相同的,維護時也需要考慮兩個對象之間的關系。但是這種模式還是很常用的。
上一章介紹了單例模式,并且指出了單例和多例的一些缺點,但是我們是不是可以采用工廠模式來實作一個單例模式的功能呢?答案是肯定的,單例模式的核心要求就是在記憶體中隻有一個對象,通過工廠方法模式也可以隻在記憶體中生産一個對象。見下面:
singleton類定義了一個private的無參構造方法,目的是不允許通過new的方式建立對象,另外,singleton類也不自己定義一個singleton對象了,因為它要通過工廠來獲得。
public class singleton {
private singleton() {
public void dosomething() {
//業務處理
既然singleton不能通過正常的管道建立一個對象,那singletonfactory如何建立一個單例對象呢?答案是通過反射方式建立:
public class singletonfactory {
private static singleton instance;
static {
try {
class clazz = class.forname(singleton.class.getname());
//擷取無參構造方法
constructor constructor = clazz.getdeclaredconstructor();
//設定無參構造方法可通路
constructor.setaccessible(true);
//産生一個執行個體對象
instance = (singleton) constructor.newinstance();
} catch (exception e) {
//異常處理
public static singleton getinstance() {
return instance;
以上通過工廠方法模式建立了一個單例對象,該架構可以繼續擴充,在一個項目中可以産生一個單例構造器,所有需要産生單例的類都遵循一定的規則(構造方法是private),然後通過擴充該架構,隻要輸入一個類型就可以獲得唯一的一個執行個體。
何為延遲初始化(lazy initialization)?即一個對象被使用完畢後,并不立刻釋放,工廠類保持其初始狀态,等待再次被使用。延遲初始化是工廠模式的一個擴充應用,其通用類表示如下:
productfactory負責産品類對象的建立工作,并且通過prmap變量産生一個緩存,對需要再次被重用的對象保留:
public class productfactory {
private static final map<string, product> prmap = new hashmap();
public static synchronized product createproduct(string type) throws exception {
//如果map中已經有這個對象
if(prmap.containskey(type)) {
product = prmap.get(type);
} else {
if(type.equals("product1")) {
product = new concreteproduct1();
}
else {
product = new concreteproduct2();
prmap.put(type, product);
return product;
代碼比較簡單,通過定義一個map容器,容納所有産生的對象,每次在new一個對象的時候先判斷map中有沒有,有就不用再new了,直接取。另外,每次new過一個對象後,也将其放入map中友善下次調用。
優點:
1. 工廠模式具有良好的封裝性,代碼結構清晰,也有利于擴充。在增加産品類的情況下,隻需要适當地修改具體的工廠類或擴充一個工廠類,就可以完成“擁抱變化”。
2. 工廠模式可以屏蔽産品類。這一點非常重要,産品類的實作如何變化,調用者都不用關系,隻需要關心産品的接口,隻要接口保持不變,系統的上層子產品就不需要發生變化。
3. 工廠模式是典型的解耦架構。高層子產品隻需要知道産品的抽象類,其他的實作類都不用關心。
工廠模式就介紹這麼多吧,如果錯誤之處,歡迎留言指正~
_____________________________________________________________________________________________________________________________________________________
-----樂于分享,共同進步!