設計模式--抽象工廠模式

抽象工廠模式【Abstract Factory Pattern】
好了,我們繼續上一節課,上一節講到女媧造人,人是造出來了,世界時熱鬧了,可是
低頭一看,都是清一色的類型,缺少關愛、仇恨、喜怒哀樂等情緒,人類的生命太平淡了,
女媧一想,猛然一拍腦袋,Shit!忘記給人類定義性別了,那怎麼辦?抹掉重來,然後就把
人類重新洗牌,準備重新開始製造人類。
由於先前的工作已經花費了很大的精力做爲鋪墊,也不想從頭開始了,那先說人類
(Product 產品類)怎麼改吧,好,有了,給每個人類都加一個性別,然後再重新制造,這
個問題解決了,那八卦爐怎麼辦?只有一個呀,要麼生產出全都是男性,要不都是女性,那
不行呀,有了,把已經有了一條生產線——八卦爐(工廠模式中的Concrete Factory)拆
開,於是女媧就使用了“八卦拷貝術”,把原先的八卦爐一個變兩個,並且略加修改,就成
了女性八卦爐(只生產女性,一個具體工廠的實現類)和男性八卦爐(只生產男性,又一個
具體工廠的實現類),這個過程的類圖如下:
先看人類(也就是產品)的類圖:
這個類圖也比較簡單,Java 的典型類圖,一個接口,幾個抽象類,然後是幾個實現類,
沒啥多說的,其中三個抽象類在抽象工廠模式中是叫做產品等級,六個實現類是叫做產品族,
這個也比較好理解,實現類嘛是真實的產品,一個叫產品,多了就叫產品族,然後再看工廠
類:
您的設計模式
第 33 頁
其中抽象工廠只實現了一個createHuman 的方法,目的是簡化實現類的代碼工作量,這
個在講代碼的時候會說。這裏還使用了Jdk 1.5 的一個新特性Enum 類型,其實這個完全可
以類的靜態變量來實現,但我想既然是學習就應該學有所獲得,即使你對這個模式非常瞭解,
也可能沒用過Enum 類型,也算是一個不同的知識點吧,我希望給大家講解,每次都有新的
技術點提出來,每個人都會有一點的收穫就足夠了,然後在具體的項目中使用時,知道有這
個技術點,然後上baidu 狗狗一下就能解決問題。話題扯遠了,我們繼續類圖,完整的類圖
如下,這個看不大清楚,其實就是上面那兩個類圖加起來,大家可以看源碼中的那個類圖文
件:
然後類圖講解完畢,我們來看程序實現:
您的設計模式
第 34 頁
package com.cbf4life;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 定義一個人類的統稱,問題出來了,剛剛定義的時候忘記定義性別了
* 這個重要的問題非修改不可,否則這個世界上太多太多的東西不存在了
*/
public interface Human {
//首先定義什麼是人類
//人是愉快的,會笑的,本來是想用smile表示,想了一下laugh更合適,好長時間
沒有大笑了;
public void laugh();
//人類還會哭,代表痛苦
public void cry();
//人類會說話
public void talk();
//定義性別
public void sex();
}
人類的接口定義好,然後根據接口創建三個抽象類,也就是三個產品等級,實現
laugh()、cry()、talk()三個方法,以AbstractYellowHuman 爲例:
package com.cbf4life.yellowHuman;
import com.cbf4life.Human;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 爲什麼要修改成抽象類呢?要定義性別呀
*/
public abstract class AbstractYellowHuman implements Human {
public void cry() {
System.out.println("黃色人種會哭");
您的設計模式
第 35 頁
}
public void laugh() {
System.out.println("黃色人種會大笑,幸福呀!");
}
public void talk() {
System.out.println("黃色人種會說話,一般說的都是雙字節");
}
}
其他的兩個抽象類AbstractWhiteHuman 和AbstractgBlackHuman 與此類似的事項方法,
不再通篇拷貝代碼,大家可以看一下源代碼。算了,還是拷貝,反正是電子檔的,不想看就
往下翻頁,也成就了部分“懶人”,不用啓動Eclipse,還要把源碼拷貝進來:
白種人的抽象類:
package com.cbf4life.whiteHuman;
import com.cbf4life.Human;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 白色人人種
* 爲了代碼整潔,新建一個包,這裏是白種人的天下了
*/
public abstract class AbstractWhiteHuman implements Human {
public void cry() {
System.out.println("白色人種會哭");
}
public void laugh() {
System.out.println("白色人種會大笑,侵略的笑聲");
您的設計模式
第 36 頁
}
public void talk() {
System.out.println("白色人種會說話,一般都是但是單字節!");
}
}
黑種人的抽象類:
package com.cbf4life.blackHuman;
import com.cbf4life.Human;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 黑色人種,記得中學學英語,老師說black man是侮辱人的意思,不懂,沒跟老外說

*/
public abstract class AbstractBlackHuman implements Human {
public void cry() {
System.out.println("黑人會哭");
}
public void laugh() {
System.out.println("黑人會笑");
}
public void talk() {
System.out.println("黑人可以說話,一般人聽不懂");
}
}
三個抽象類都實現完畢了,然後就是些實現類了。其實,你說抽象類放這裏有什麼意義
嗎?就是不允許你new 出來一個抽象的對象唄,使用非抽象類完全就可以代替,呵呵,殺豬
殺尾巴,各有各的殺法,不過既然進了Java 這個門就要遵守Java 這個規矩,我們看實現類:
您的設計模式
第 37 頁
女性黃種人的實現類:
package com.cbf4life.yellowHuman;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 女性黃種人
*/
public class YellowFemaleHuman extends AbstractYellowHuman {
public void sex() {
System.out.println("該黃種人的性別爲女...");
}
}
男性黃種人的實現類:
package com.cbf4life.yellowHuman;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 男性黃種人
*/
public class YellowMaleHuman extends AbstractYellowHuman {
public void sex() {
System.out.println("該黃種人的性別爲男....");
}
}
女性白種人的實現類:
package com.cbf4life.whiteHuman;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.\
* 女性白種人
*/
public class WhiteFemaleHuman extends AbstractWhiteHuman {
您的設計模式
第 38 頁
public void sex() {
System.out.println("該白種人的性別爲女....");
}
}
男性白種人的實現類:
package com.cbf4life.whiteHuman;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 男性白種人
*/
public class WhiteMaleHuman extends AbstractWhiteHuman {
public void sex() {
System.out.println("該白種人的性別爲男....");
}
}
女性黑種人的實現類:
package com.cbf4life.blackHuman;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 女性黑種人
*/
public class BlackFemaleHuman extends AbstractBlackHuman {
public void sex() {
System.out.println("該黑種人的性別爲女...");
}
}
您的設計模式
第 39 頁
男性黑種人的實現類:
package com.cbf4life.blackHuman;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 男性黑種人
*/
public class BlackMaleHuman extends AbstractBlackHuman {
public void sex() {
System.out.println("該黑種人的性別爲男...");
}
}
抽象工廠模式下的產品等級和產品族都已經完成,也就是人類以及產生出的人類是什麼
樣子的都已經定義好了,下一步就等着工廠開工創建了,那我們來看工廠類。
在看工廠類之前我們先看那個枚舉類型,這個是很有意思的:
package com.cbf4life;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 世界上有哪些類型的人,列出來
* JDK 1.5開始引入enum類型也是目的的,吸引C程序員轉過來
*/
public enum HumanEnum {
//把世界上所有人類型都定義出來
YelloMaleHuman("com.cbf4life.yellowHuman.YellowMaleHuman"),
YelloFemaleHuman("com.cbf4life.yellowHuman.YellowFemaleHuman")
,
WhiteFemaleHuman("com.cbf4life.whiteHuman.WhiteFemaleHuman"),
WhiteMaleHuman("com.cbf4life.whiteHuman.WhiteMaleHuman"),
BlackFemaleHuman("com.cbf4life.blackHuman.BlackFemaleHuman"),
您的設計模式
第 40 頁
BlackMaleHuman("com.cbf4life.blackHuman.BlackMaleHuman");
private String value = "";
//定義構造函數,目的是Data(value)類型的相匹配
private HumanEnum(String value){
this.value = value;
}
public String getValue(){
return this.value;
}
/*
* java enum類型儘量簡單使用,儘量不要使用多態、繼承等方法
* 畢竟用Clas完全可以代替enum
*/
}
我之所以引入Enum 這個類型,是想讓大家在看這本書的時候能夠隨時隨地的學到點什
麼,你如果看不懂設計模式,你可以從我的程序中學到一些新的技術點,不用像我以前報着
磚頭似的書在那裏啃,看一遍不懂,再看第二遍,然後翻了英文原本才知道,哦~,原來是
這樣滴,只能說有些翻譯家實在不懂技術。我在講解技術的時候,儘量少用專業術語,儘量
使用大部分人類都能理解的語言。
Enum 以前我也很少用,最近在一個項目中偶然使用上了,然後才發覺它的好處,Enum
類型作爲一個參數傳遞到一個方法中時,在Junit 進行單元測試的時候,不用判斷輸入參數
是否爲空、長度爲0 的邊界異常條件,如果方法傳入的參數不是Enum 類型的話,根本就傳
遞不進來,你說定義一個類,定義一堆的靜態變量,這也可以呀,這個不和你擡槓,上面的
代碼我解釋一下,構造函數沒啥好說的,然後是getValue()方法,就是獲得枚舉類型中一
個元素的值,枚舉類型中的元素也是有名稱和值的,這個和HashMap 有點類似。
然後,我們看我們的工廠類,先看接口:
package com.cbf4life;
您的設計模式
第 41 頁
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 這次定一個接口,應該要造不同性別的人,需要不同的生產線
* 那這個八卦爐必須可以製造男人和女人
*/
public interface HumanFactory {
//製造黃色人種
public Human createYellowHuman();
//製造一個白色人種
public Human createWhiteHuman();
//製造一個黑色人種
public Human createBlackHuman();
}
然後看抽象類:
package com.cbf4life.humanFactory;
import com.cbf4life.Human;
import com.cbf4life.HumanEnum;
import com.cbf4life.HumanFactory;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 編寫一個抽象類,根據enum創建一個人類出來
*/
public abstract class AbstractHumanFactory implements HumanFactory
{
/*
* 給定一個性別人種,創建一個人類出來專業術語是產生產品等級
*/
protected Human createHuman(HumanEnum humanEnum) {
Human human = null;
//如果傳遞進來不是一個Enum中具體的一個Element的話,則不處理
if (!humanEnum.getValue().equals("")) {
try {
//直接產生一個實例
您的設計模式
第 42 頁
human = (Human)
Class.forName(humanEnum.getValue()).newInstance();
} catch (Exception e) {
//因爲使用了enum,這個種異常情況不會產生了,除非你的enum有問
題;
e.printStackTrace();
}
}
return human;
}
}
看到沒,這就是引入enum 的好處,createHuman(HumanEnum humanEnum)這個方法定義
了輸入參數必須是HumanEnum 類型,然後直接使用humanEnum.getValue()方法就能獲得具
體傳遞進來的值,這個不多說了,大家自己看程序領會,沒多大難度,這個抽象類的目的就
是減少下邊實現類的代碼量,我們看實現類:
男性工廠,只創建男性:
package com.cbf4life.humanFactory;
import com.cbf4life.Human;
import com.cbf4life.HumanEnum;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 男性創建工廠
*/
public class MaleHumanFactory extends AbstractHumanFactory {
//創建一個男性黑種人
public Human createBlackHuman() {
return super.createHuman(HumanEnum.BlackMaleHuman);
}
//創建一個男性白種人
public Human createWhiteHuman() {
return super.createHuman(HumanEnum.WhiteMaleHuman);
}
//創建一個男性黃種人
您的設計模式
第 43 頁
public Human createYellowHuman() {
return super.createHuman(HumanEnum.YelloMaleHuman);
}
}
女性工廠,只創建女性:
package com.cbf4life.humanFactory;
import com.cbf4life.Human;
import com.cbf4life.HumanEnum;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.\
* 女性創建工廠
*/
public class FemaleHumanFactory extends AbstractHumanFactory {
//創建一個女性黑種人
public Human createBlackHuman() {
return super.createHuman(HumanEnum.BlackFemaleHuman);
}
//創建一個女性白種人
public Human createWhiteHuman() {
return super.createHuman(HumanEnum.WhiteFemaleHuman);
}
//創建一個女性黃種人
public Human createYellowHuman() {
return super.createHuman(HumanEnum.YelloFemaleHuman);
}
}
產品定義好了,工廠也定義好了,萬事俱備只欠東風,那咱就開始造吧,哦,不對,女
媧開始造人了:
package com.cbf4life;
您的設計模式
第 44 頁
import com.cbf4life.humanFactory.FemaleHumanFactory;
import com.cbf4life.humanFactory.MaleHumanFactory;
/**
* @author cbf4Life [email protected]
* I'm glad to share my knowledge with you all.
* 女媧建立起了兩條生產線,分別是:
* 男性生產線
* 女性生產線
*/
public class NvWa {
public static void main(String[] args) {
//第一條生產線,男性生產線
HumanFactory maleHumanFactory = new MaleHumanFactory();
//第二條生產線,女性生產線
HumanFactory femaleHumanFactory = new FemaleHumanFactory();
//生產線建立完畢,開始生產人了:
Human maleYellowHuman =
maleHumanFactory.createYellowHuman();
Human femaleYellowHuman =
femaleHumanFactory.createYellowHuman();
maleYellowHuman.cry();
maleYellowHuman.laugh();
femaleYellowHuman.sex();
/*
* .....
* 後面你可以續了
*/
}
}
兩個八卦爐,一個造女的,一個造男的,開足馬力,一直造到這個世界到現在這個模式
爲止。
抽象工廠模式講完了,那我們再思考一些問題:工廠模式有哪些優缺點?先說優點,我
這人一般先看人優點,非常重要的有點就是,工廠模式符合OCP 原則,也就是開閉原則,怎
麼說呢,比如就性別的問題,這個世界上還存在雙性人,是男也是女的人,那這個就是要在
您的設計模式
第 45 頁
我們的產品族中增加一類產品,同時再增加一個工廠就可以解決這個問題,不需要我再來實
現了吧,很簡單的大家自己畫下類圖,然後實現下。
那還有沒有其他好處呢?抽象工廠模式,還有一個非常大的有點,高內聚,低耦合,在
一個較大的項目組,產品是由一批人定義開發的,但是提供其他成員訪問的時候,只有工廠
方法和產品的接口,也就是說只需要提供Product Interface 和Concrete Factory 就可以
產生自己需要的對象和方法,Java 的高內聚低耦合的特性表現的一覽無遺,哈哈。
您的設計模式
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章