目錄
- 回顧眾多工廠模式
- 抽象工廠模式的理念
- 抽象工廠模式與工廠方法模式的差異
- 怎么來實現(xiàn)抽象工廠模式
- 抽象工廠模式在Android源碼中的應用
回顧眾多工廠模式
簡單工廠模式
對簡單工廠模式還不了解的可以查看下我的歷史文章 簡單工廠模式,簡單工廠模式的核心是使用工廠實現(xiàn)選擇創(chuàng)建產品實現(xiàn),這應該很好理解端衰。
工廠方法模式
對工廠方法模式還不了解的可以查看下我的歷史文工廠方法模式拧晕。工廠方法模式的核心是將選擇創(chuàng)建產品實現(xiàn)的過程宇整,延遲到子類去完成宾符,這也是相對比較好理解的模式晃酒。
抽象工廠模式的理念
第一節(jié)的回顧故源,我們復習了簡單工廠與工廠方法模式紊遵。由此我們也會使用 UML 圖線畫出對抽象工廠模式的理解账千,然后我們在對比三張 UML 圖來分析他們之間的設計是如何演進或取舍的。
抽象工廠模式強調了產品簇的概念暗膜,那么什么是產品簇呢匀奏?在抽象工廠模式中,產品簇是指工廠生產出的產品們之間彼此具備強關聯(lián)桦山。比如:AK47工廠生產的 AK47步槍攒射、AK47專配的子彈,一旦 AK47裝錯了子彈是無法正常開槍的(甚至會炸膛)恒水。
抽象工廠模式與工廠方法模式的差異
剛開始接觸抽象工廠模式的時候会放,我就是不能理解抽象工廠模式與工廠方法模式的區(qū)別,也許屏幕前的你也有一樣的困惑钉凌。但經過一段時間時間的思考與實踐咧最,我逐漸的明白它們之間的差異。
工廠方法模式生產產品的形式就像 移動手機大賣場(上圖)御雕。賣場里面只賣手機矢沿,這些手機里面可能有 三星、華為酸纲、OPPO捣鲸、金立、蘋果闽坡、HTC栽惶、Nokia 等類別,但無論如何它都沒有跳出手機的范疇疾嗅。因此想買手機的客戶外厂,直接去大賣場總能挑選到心儀的手機,因為手機(工廠生產的產品實例)太多了代承。
而抽象工廠模式生產產品的形式則更像是蘋果零售店(上圖)汁蝶,除了賣手機之外還提供Mac、路由器论悴、耳機掖棉、iPad、iPod 等電子產品膀估。作為一個對品質(逼格)有要求的客戶幔亥,會直接去蘋果零售店里購買手機,一時興起再買一臺 Mac 也是可以的玖像。
無論手機大賣場和蘋果零售店都是可以買到手機的,但是針對的客戶群體顯然是不一樣的。同樣的捐寥,工廠方法模式 與 抽象工廠模式 針對的客戶群體也是不一樣的笤昨,不過它們都擁有 生產產品 這一職責。
- 工廠方法模式:
讓單一產品線上的產品更易被擴展
握恳。 - 抽象工廠模式:
讓多條 {單一產品線上的產品更易被擴展} 的同時瞒窒,能夠讓多條線上的產品保持約束
。
如上圖乡洼,橫向有兩條產品線(手機崇裁、電腦),縱向有三個產品簇(蘋果束昵、三星拔稳、小米)。當我們不需要考慮產品簇時锹雏,為工廠方法模式巴比。反之,就是抽象工廠模式礁遵。
怎么來實現(xiàn)抽象工廠模式
可以發(fā)現(xiàn)在目錄層級上與工廠方法模式并沒有區(qū)別轻绞,差異在工廠的組織形式上。
先定義產品接口
public interface IPhone {
void screen();
void micro();
void battery();
void usb();
// XXX just for test
void printLog();
}
產品實現(xiàn)類
蘋果手機佣耐,及電腦的實現(xiàn)類就省略了政勃。
public class XiaoMiPhoneImpl implements IPhone {
private String TAG = "小米手機";
@Override
public void screen() {
System.out.println(TAG + "屏幕");
}
@Override
public void micro() {
System.out.println(TAG + "麥克風");
}
@Override
public void battery() {
System.out.println(TAG + "電池");
}
@Override
public void usb() {
System.out.println(TAG + "usb插口");
}
@Override
public void printLog() {
screen();
micro();
battery();
usb();
}
}
定義工廠接口
實際生活中可能無法提取工廠接口,畢竟每個工廠生產的產品不可能都保持一致兼砖。在這里定義接口的目的是想強調:這是縱向的產品簇奸远。
public interface IFactory {
void createPhone();
void createComputer();
}
定義小米工廠
public class XiaoMiFactoryImpl implements IFactory {
@Override
public void createPhone() {
IPhone phone = new XiaoMiPhoneImpl();
phone.printLog();
}
@Override
public void createComputer() {
IComputer computer = new XiaoMiComputerImpl();
computer.printLog();
}
}
客戶端調用測試
public class Client {
public static void main(String[] args) {
IFactory factory = new XiaoMiFactoryImpl();
factory.createPhone();
factory.createComputer();
}
}
測試結果
小米手機屏幕
小米手機麥克風
小米手機電池
小米手機usb插口
小米電腦屏幕
小米電腦鍵盤
小米電腦鼠標
小米電腦usb
在理解了思想的前提下,編寫這些代碼是相當簡單的掖鱼。
抽象工廠模式在Android源碼中的應用
com.android.internal.policy.IPolicy
IPolicy 是產生窗口屏幕相關對象的抽象接口然走,在 android 源碼中,Policy 是 IPolicy 的唯一一個實現(xiàn)戏挡,用于生成對象集合芍瑞。Policy 創(chuàng)建了一系列的對象(PhoneWindow、PhoneLayoutInflater褐墅、PhoneWindowManager拆檬、PhoneFallbackEventHandler)。從UML圖就可以看出妥凳,IPolicy算是一個典型的抽象工廠竟贯,只不過在源碼中只有一個具體的工廠實現(xiàn)。
另外Policy的實現(xiàn)還有一點特殊的地方逝钥,它使用static域將他需要創(chuàng)建的對象都預先load出來屑那,也就是說當虛擬機加載Policy類的時候,就會加載它創(chuàng)建的對象的class。
定義工廠接口
public interface IPolicy {
public Window makeNewWindow(Context context);
public LayoutInflater makeNewLayoutInflater(Context context);
public WindowManagerPolicy makeNewWindowManager();
public FallbackEventHandler makeNewFallbackEventHandler(Context context);
}
定義工廠實現(xiàn)類
public class Policy implements IPolicy {
private static final String TAG = "PhonePolicy";
private static final String[] preload_classes = {
"com.android.internal.policy.impl.PhoneLayoutInflater",
"com.android.internal.policy.impl.PhoneWindow",
"com.android.internal.policy.impl.PhoneWindow$1",
"com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback",
"com.android.internal.policy.impl.PhoneWindow$DecorView",
"com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
"com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
};
static {
// For performance reasons, preload some policy specific classes when
// the policy gets loaded.
for (String s : preload_classes) {
try {
Class.forName(s);
} catch (ClassNotFoundException ex) {
Log.e(TAG, "Could not preload class for phone policy: " + s);
}
}
}
public Window makeNewWindow(Context context) {
return new PhoneWindow(context);
}
public LayoutInflater makeNewLayoutInflater(Context context) {
return new PhoneLayoutInflater(context);
}
public WindowManagerPolicy makeNewWindowManager() {
return new PhoneWindowManager();
}
public FallbackEventHandler makeNewFallbackEventHandler(Context context) {
return new PhoneFallbackEventHandler(context);
}
}
定義產品類 (Window
)
代碼太多持际,咱就不貼了沃琅。
定義產品實現(xiàn)類(PhoneWindow
)
代碼太多,咱就不貼了蜘欲。
為什么不用4個單獨的工廠(工廠方法模式)去實現(xiàn)呢益眉?
其實四種不同的產品(Window,WindowManagerPolicy姥份,LayoutInflater郭脂,F(xiàn)allbackEventHandler),如果用四個工廠方法也是可以的澈歉,但是會缺乏將本來應該有相互關聯(lián)的產品拆分開了展鸡,抽象工廠一定程度上提高了它們之間的內聚。
假如除了Phone外闷祥,如果需要加入新的產品簇(比如說TV娱颊,智能手表),那么只需要創(chuàng)建一個對應Policy凯砍,以及對應的產品系列箱硕,然后將PolicyManager的IPolicy指向新產品簇的Policy就好了。