概述
抽象原廠模式是對象的建立模式,它是Factory 方法模式的進一步推廣。
假設一個子系統需要一些產品對象,而這些產品又屬於一個以上的產品等級結構。那麼為了將消費這些產品對象的責任和建立這些產品對象的責任分割開來,可以引進抽象原廠模式。這樣的話,消費產品的一方不需要直接參与產品的建立工作,而只需要向一個公用的工廠介面請求所需要的產品。
通過使用抽象原廠模式,可以處理具有相同(或者相似)等級結構中的多個產品族中的產品對象的建立問題。如下圖所示:
根據產品角色的結構圖,就不難給出工廠角色的結構設計圖。
可以看出,每一個工廠角色都有兩個Factory 方法,分別負責建立分屬不同產品等級結構的產品對象。
抽象工廠的功能是為一系列相關對象或相互依賴的對象建立一個介面。一定要注意,這個介面內的方法不是任意堆砌的,而是一系列相關或相互依賴的方法。比如上面例子中的主板和CPU,都是為了組裝一台電腦的相關對象。不同的裝機方案,代表一種具體的電腦系列。
由於抽象工廠定義的一系列對象通常是相關或相互依賴的,這些產品對象就構成了一個產品族,也就是抽象工廠定義了一個產品族。
這就帶來非常大的靈活性,切換產品族的時候,只要提供不同的抽象工廠實現就可以了,也就是說現在是以一個產品族作為一個整體被切換。
核心
先上一張圖:
我們還是以苦逼的程式猿為例來說抽象原廠模式的一些核心概念。通過上圖你可以發現,橫縱二維座標可以確定平面上一個唯一的點,這也就是抽象工廠的核心。
產品等級結構:就是繼承結構。就像上面Android,IOS,PHP這些技能繼承自一個抽象的技能類(譬如前面的ICode),這個抽象類別與這些子類構成了產品等級結構。 同理的Android書,C語言書,指令碼書繼承自一個工具書類,這個工具書抽象類別與這些子類構成了等級結構。
產品族:抽象原廠模式中的產品族官方定義是指由同一個工廠生產的,位於不同產品等級結構中的一組產品。 譬如上面的Android位於技能等級結構中,Android書位於工具書等級結構中,Android技能和Android書是位於不同產品結構的一組產品,但是任何一個程式猿都需要具備技能和工具書, 譬如一個Android程式猿需要有Android技能及Android書,所以這個Android程式猿就是一個產品族。
概念: 提供一個建立一系列相關或相互依賴對象的介面,而無須指定它們具體的類。抽象原廠模式又稱為Kit模式,它是一種對象建立型模式。
重點: 抽象原廠模式結構重要核心模組:
抽象工廠:
聲明一組用於建立一族產品的方法,每一個方法對應一種產品。
具體工廠:
實現了在抽象工廠中聲明的建立產品的方法,產生一組具體產品,這些產品構成了一個產品族,每一個產品都位於某個產品等級結構中。
抽象產品:
它為每種產品聲明介面,在抽象產品中聲明了產品所具有的業務方法。
具體產品:
定義具體工廠生產的具體產品對象,實現抽象產品介面中聲明的業務方法。
使用情境:
當需要建立的對象是一系列相互關聯或相互依賴的產品族時,便可以使用抽象原廠模式。 大白話意思就是一個繼承體系中,如果存在著多個等級結構(即存在著多個抽象類別,像上面的技能與工具書), 並且分屬各個等級結構中的實作類別之間存在著一定的關聯或者約束,就可以使用抽象原廠模式。當然了, 同樣的道理就是如果各個等級結構中的實作類別之間不存在關聯或約束,則使用多個獨立的工廠來對產品進行建立。
程式執行個體
如下執行個體就是上圖何如上文字解釋的實現代碼,具體不再解釋:
複製代碼 代碼如下:
package yanbober.github.io;
/*技能等級結構部分*/
interface ICode {
void coding();
}
class CodeImplAndroid implements ICode {
@Override
public void coding() {
System.out.println("Coding Android!");
}
}
class CodeImplPHP implements ICode {
@Override
public void coding() {
System.out.println("Coding PHP!");
}
}
/*工具書等級結構*/
interface INeedBook {
void lookBook();
}
class NeedBookImplAndroid implements INeedBook {
@Override
public void lookBook() {
System.out.println("Look Android Book!");
}
}
class NeedBookImplPHP implements INeedBook {
@Override
public void lookBook() {
System.out.println("Look PHP Book!");
}
}
/*產品族*/
interface IAbstractFactory {
ICode getCodingSkill();
INeedBook getNeedBook();
}
class FactoryImplAndroid implements IAbstractFactory {
@Override
public ICode getCodingSkill() {
return new CodeImplAndroid();
}
@Override
public INeedBook getNeedBook() {
return new NeedBookImplAndroid();
}
}
class FactoryImplPHP implements IAbstractFactory {
@Override
public ICode getCodingSkill() {
return new CodeImplPHP();
}
@Override
public INeedBook getNeedBook() {
return new NeedBookImplPHP();
}
}
public class Main {
public static void main(String[] args) {
IAbstractFactory factory = new FactoryImplAndroid();
ICode code = factory.getCodingSkill();
INeedBook book = factory.getNeedBook();
code.coding();
book.lookBook();
factory = new FactoryImplPHP();
code = factory.getCodingSkill();
book = factory.getNeedBook();
code.coding();
book.lookBook();
}
}
技巧Tips:依舊可以使用配置與反射實現自動適應。
總結一把
抽象原廠模式的優點:
和前面一樣,隔離具體類的產生,使客戶並不需要知道什麼被建立。
增加新的產品族很方便,無須修改已有系統,符合“開閉原則”。
抽象原廠模式的缺點:
增加新的產品等級結構麻煩,需要對原有系統進行較大的修改,甚至需要修改抽象層代碼,違背“開閉原則”。