0x01 前言
??繼上一篇文章所述,抽象工廠模式(Abstract Factory Pattern)是圍繞一個(gè)超級工廠創(chuàng)建其他工廠。該超級工廠又稱為其他工廠的工廠。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式。
??在抽象工廠模式中,接口是負(fù)責(zé)創(chuàng)建一個(gè)相關(guān)對象的工廠,不需要顯式指定它們的類。每個(gè)生成的工廠都能按照工廠模式提供對象。
0x02 簡介
意圖:提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定它們具體的類。
主要解決:主要解決接口選擇的問題。
何時(shí)使用:系統(tǒng)的產(chǎn)品有多于一個(gè)的產(chǎn)品族,而系統(tǒng)只消費(fèi)其中某一族的產(chǎn)品。
如何解決:在一個(gè)產(chǎn)品族里面,定義多個(gè)產(chǎn)品。
關(guān)鍵代碼:在一個(gè)工廠里聚合多個(gè)同類產(chǎn)品。
應(yīng)用實(shí)例:工作了,為了參加一些聚會(huì),肯定有兩套或多套衣服吧,比如說有商務(wù)裝(成套,一系列具體產(chǎn)品)、時(shí)尚裝(成套,一系列具體產(chǎn)品),甚至對于一個(gè)家庭來說,可能有商務(wù)女裝、商務(wù)男裝、時(shí)尚女裝、時(shí)尚男裝,這些也都是成套的,即一系列具體產(chǎn)品。假設(shè)一種情況(現(xiàn)實(shí)中是不存在的,要不然,沒法進(jìn)入共產(chǎn)主義了,但有利于說明抽象工廠模式),在您的家中,某一個(gè)衣柜(具體工廠)只能存放某一種這樣的衣服(成套,一系列具體產(chǎn)品),每次拿這種成套的衣服時(shí)也自然要從這個(gè)衣柜中取出了。用 OO 的思想(面向?qū)ο螅┤ダ斫?,所有的衣柜(具體工廠)都是衣柜類的(抽象工廠)某一個(gè),而每一件成套的衣服又包括具體的上衣(某一具體產(chǎn)品),褲子(某一具體產(chǎn)品),這些具體的上衣其實(shí)也都是上衣(抽象產(chǎn)品),具體的褲子也都是褲子(另一個(gè)抽象產(chǎn)品)。
優(yōu)點(diǎn):當(dāng)一個(gè)產(chǎn)品族中的多個(gè)對象被設(shè)計(jì)成一起工作時(shí),它能保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對象。
缺點(diǎn):產(chǎn)品族擴(kuò)展非常困難,要增加一個(gè)系列的某一產(chǎn)品,既要在抽象的 Creator 里加代碼,又要在具體的里面加代碼。
使用場景: 1、QQ 換皮膚,一整套一起換。 2、生成不同操作系統(tǒng)的程序。
注意事項(xiàng):產(chǎn)品族難擴(kuò)展,產(chǎn)品等級易擴(kuò)展。
0x03 設(shè)計(jì)概述
??抽象工廠模式是工廠方法模式的升級版本,他用來創(chuàng)建一組相關(guān)或者相互依賴的對象。
??抽象工廠模式時(shí)代:隨著客戶的要求越來越高,需要定制不同組合的電腦。例如聯(lián)想 Y 系列,華碩 G 系列,聯(lián)想 Y 配備性能級顯卡,聯(lián)想 G 配備發(fā)燒級顯卡。那么并不需要?jiǎng)?chuàng)辦一個(gè)生產(chǎn)聯(lián)想 Y 性能級顯卡電腦的工廠、華碩 G 發(fā)燒級顯卡電腦的工廠。而僅僅是抽象一個(gè)工廠,用來生產(chǎn)聯(lián)想 Y 電腦、華碩 G 電腦、性能級顯卡、發(fā)燒級顯卡,然后組合就形成產(chǎn)品。
0x04 具體實(shí)現(xiàn)
抽象工廠時(shí)代
項(xiàng)目結(jié)構(gòu)圖
產(chǎn)品類
??為產(chǎn)品顯卡創(chuàng)建接口。
// factory_pattern.abstract_factory.product.IGraphics
public interface IGraphics {
void getGraphics(String series);
}
??為產(chǎn)品電腦創(chuàng)建接口。
// factory_pattern.abstract_factory.product.IComputer
public interface IComputer {
void getComputer(String brand);
}
??拓展上述接口,采用需要組合的方式生產(chǎn)產(chǎn)品,所以將類進(jìn)行細(xì)分拓展接口。
??拓展顯卡接口 IGraphics ,定義性能級顯卡類 PerformanceGraphics 。
// factory_pattern.abstract_factory.product.impl.PerformanceGraphics
public class PerformanceGraphics implements IGraphics {
@Override
public void getGraphics(String series) {
System.out.println("研發(fā)一個(gè) " + series + " 顯卡");
}
}
??拓展顯卡接口 IGraphics ,定義發(fā)燒級顯卡類 FeverGraphics 。
// factory_pattern.abstract_factory.product.impl.FeverGraphics
public class FeverGraphics implements IGraphics {
@Override
public void getGraphics(String series) {
System.out.println("制造一個(gè) " + series + " 顯卡");
}
}
??拓展電腦接口 IComputer ,定義聯(lián)想電腦類 LenovoComputer 。
// factory_pattern.abstract_factory.product.impl.LenovoComputer
public class LenovoComputer implements IComputer {
@Override
public void getComputer(String brand) {
System.out.println("制造一臺(tái) " + brand + " 筆記本電腦");
}
}
??拓展電腦接口 IComputer ,定義華碩電腦類 AsusComputer 。
// factory_pattern.abstract_factory.product.impl.AsusComputer
public class AsusComputer implements IComputer {
@Override
public void getComputer(String brand) {
System.out.println("研發(fā)一臺(tái) " + brand + " 臺(tái)式電腦");
}
}
工廠類
??為 Computer 和 Graphics 對象創(chuàng)建接口 IAbstractFactory 來獲取工廠。
// factory_pattern.abstract_factory.factory.IAbstractFactory
public interface IAbstractFactory {
IComputer createComputer(String brand);
IGraphics createGraphics(String series);
}
??創(chuàng)建擴(kuò)展了 IAbstractFactory 的工廠接口,基于給定的信息生成實(shí)體類的對象。
// factory_pattern.abstract_factory.factory.impl.GraphicsFactroy
public class GraphicsFactroy implements IAbstractFactory {
@Override
public IComputer createComputer(String brand) {
return null;
}
@Override
public IGraphics createGraphics(String series) {
switch (series) {
case "Performance" :
return new PerformanceGraphics();
case "Fever" :
return new FeverGraphics();
default :
throw new IllegalArgumentException();
}
}
}
// factory_pattern.abstract_factory.factory.impl.ComputerFactory
public class ComputerFactory implements IAbstractFactory {
@Override
public IComputer createComputer(String brand) {
switch (brand) {
case "Lenovo" :
return new LenovoComputer();
case "Asus" :
return new AsusComputer();
default :
throw new IllegalArgumentException();
}
}
@Override
public IGraphics createGraphics(String series) {
return null;
}
}
??創(chuàng)建一個(gè)工廠創(chuàng)造器 / 生成器類,通過傳遞品牌或型號來獲取工廠。
// factory_pattern.abstract_factory.factory.impl.FactoryProducer
public class FactoryProducer {
public static IAbstractFactory getFactory(String choice){
switch (choice) {
case "Computer" :
return new ComputerFactory();
case "Graphics" :
return new GraphicsFactroy();
default :
throw new IllegalArgumentException();
}
}
}
用戶類
??使用 FactoryProducer 來獲取 IAbstractFactory,通過傳遞類型信息來獲取實(shí)體類的對象。
// factory_pattern.abstract_factory.user.ComputerTest
public class ComputerTest {
@Test
public void testGetLenovoPerformanceComputer() {
IAbstractFactory computerFactory = FactoryProducer.getFactory("Computer");
IComputer lenPC = computerFactory.createComputer("Lenovo");
IAbstractFactory graphicsFactory = FactoryProducer.getFactory("Graphics");
IGraphics lenPer = graphicsFactory.createGraphics("Performance");
lenPC.getComputer("Lenovo");
lenPer.getGraphics("Performance");
}
@Test
public void testGetAsusFeverComputer() {
IAbstractFactory computerFactory = FactoryProducer.getFactory("Computer");
IComputer lenPC = computerFactory.createComputer("Asus");
IAbstractFactory graphicsFactory = FactoryProducer.getFactory("Graphics");
IGraphics lenPer = graphicsFactory.createGraphics("Fever");
lenPC.getComputer("Asus");
lenPer.getGraphics("Fever");
}
}
驗(yàn)證輸出
testGetLenovoPerformanceComputer
制造一臺(tái) Lenovo 筆記本電腦
研發(fā)一個(gè) Performance 顯卡
testGetAsusFeverComputer
研發(fā)一臺(tái) Asus 臺(tái)式電腦
制造一個(gè) Fever 顯卡
0x05 總結(jié)
??無論是簡單工廠,工廠方法模式,還是抽象工廠模式,他們都屬于工廠模式,在形式和特點(diǎn)上也是極為相似的,他們的最終目的都是為了解耦。在使用時(shí),我們不必去在意這個(gè)模式到底工廠方法模式還是抽象工廠模式,因?yàn)樗麄冎g的演變常常是令人琢磨不透的。經(jīng)常你會(huì)發(fā)現(xiàn),明明使用的工廠方法模式,當(dāng)新需求來臨,稍加修改,加入了一個(gè)新方法后,由于類中的產(chǎn)品構(gòu)成了不同等級結(jié)構(gòu)中的產(chǎn)品族,它就變成抽象工廠模式了。而對于抽象工廠模式,當(dāng)減少一個(gè)方法使的提供的產(chǎn)品不再構(gòu)成產(chǎn)品族之后,它就演變成了工廠方法模式。
??所以,在使用工廠模式時(shí),只需要關(guān)心降低耦合度的目的是否達(dá)到了。