抽象工廠模式
抽象工廠模式用來解決產品族的實例化問題。比如說現在有個家居設計軟件,通過軟件模擬房間,擺放各種虛擬的家具,看效果如何。我們可以放入電視柜、茶幾、餐桌、床等等。這一系列的家具就叫做產品族。產品族面臨的問題是,當一個產品族切換到另外一個產品族時,如何讓代碼的修改最小。也就是說如何做到開閉原則。
想把設計好的方案從簡約現代切換到歐式風格家具,怎么才能做到修改最???如果采用簡單工廠,那么每種產品都對應一個工廠,工廠負責產出不同風格的產品。設計方案中用到 n 種產品就要修改 n 處代碼。這顯然不是最佳的方法。此時,我們需要抽象工廠模式來解決這個問題。抽象工廠模式中,每個工廠的實現負責生產自己產品族的產品。示意圖如下:
1. 實現抽象工廠
為了便于理解和展示,我們假設只有兩種家具----椅子和桌子。
首先定義每種家具的接口,只有一個方法用來獲取家具說明。
椅子:
public interface Chair {
void getChairIntroduction();
}
桌子:
public interface Desk {
void getDeskIntroduction();
}
以椅子為例,我們分別實現簡約現代和歐式兩種風格。
簡約現代風格椅子:
public class ModernStyleChair implements Chair {
@Override
public void getChairIntroduction() {
System.out.println("這是一個現代簡約風格的椅子");
}
}
歐式風格椅子:
public class EuropeanStyleChair implements Chair {
@Override
public void getChairIntroduction() {
System.out.println("這是一個歐式風格的椅子");
}
}
桌子也有兩種實現,代碼這里省略。
產品我們已經編寫完成。接下來我們來看看工廠的代碼。
首先我們定義一個家具工廠接口,可以生產椅子和桌子:
public interface FurnitureFactory {
Chair createChair();
Desk createDesk();
}
由于我們支持兩種不同的風格,所以我們編寫兩個實現類。
簡約風格家具工廠:
public class ModernFurnitureFactory implements FurnitureFactory{
@Override
public Chair createChair() {
return new ModernStyleChair();
}
@Override
public Desk createDesk() {
return new ModernStyleDesk();
}
}
歐式風格家具工廠:
public class EuropeanFurnitureFactory implements FurnitureFactory{
@Override
public Chair createChair() {
return new EuropeanStyleChair();
}
@Override
public Desk createDesk() {
return new EuropeanStyleDesk();
}
}
上面的代碼中,每種工廠各自實現如何生產兩種不同的家具。
客戶端代碼如下:
public class Client {
public static void main(String[] args) {
FurnitureFactory furnitureFactory = new EuropeanFurnitureFactory();
Chair chair = furnitureFactory.createChair();
Desk desk = furnitureFactory.createDesk();
chair.getChairIntroduction();
desk.getDeskIntroduction();
}
}
客戶端代碼中,我們實例化的是歐式家具工廠,那么所生產的椅子和桌子應該是歐式風格。執行后輸出如下:
這是一個歐式風格的椅子
這是一個歐式風格的桌子
和我們的預期相符。如果想要更換產品族,從現代簡約切換到歐式,我們只需要修改一處代碼。
FurnitureFactory furnitureFactory = new ModernFurnitureFactory();
僅通過更換抽象工廠的實現即可實現。修改后執行結果如下:
這是一個現代簡約風格的椅子
這是一個現代簡約風格的桌子
可以看到已經切換到簡約風格的產品族。這個過程中并不需要改任何產品使用的代碼。
如果增加別的風格產品族,只需要新建新風格的產品族產品,增加新風格產品族的工廠實現即可。
類圖:
2. 抽象工廠優缺點
2.1 優點
- 分離了產品類和客戶端類:客戶端只依賴抽象的產品接口。此外,如何生產產品被封裝在工廠內部;
- 方便切換產品族:客戶端代碼只需要初始化一次工廠實現。這意味著在切換產品族的時候,只需要修改一行代碼,換一個工廠實現即可;
- 保證產品的一致性:使用抽象工廠,可以保證你從相同工廠生產的產品都屬于同一個產品族。不會出現椅子是現代簡約風格,而桌子是歐式風格的情況。
2.2 缺點
添加新的產品時,改動較多。例子從兩個維度定義產品,一是不同產品,比如桌子、椅子。另外是不同族,例如現代簡約和歐式。使用抽象工廠,優化了產品族,也就是第二個維度變化的難度。但是當添加新的產品時改動就會比較多。比如我們要添加一個新的產品是電視柜。那么需要修改抽象工廠,添加生產電視柜的方法。此外,有幾種工廠的實現,我們就需要修改幾個類,添加具體的生產實現。
3. 抽象工廠適用場景
- 你的系統中,需要使用不同產品族中的某一個產品族來操作。 比如說DB源。如果想切換DB,只需要切換DB源即可,其他代碼基本上不需要改動;
- 你的系統中,需要保證某些產品的一致性。 比如操作系統的外觀,當切換到夜間模式時,所有的組件都會換為夜間模式風格。
4. 小結
抽象工廠可以做到一組產品的使用和生產相分離。通過抽象工廠模式,我們切換一組產品族的,只需要更換抽象工廠實現即可。由于產品生產被分離出去,所以添加新的產品族完全通過擴展來實現的。很好的實現了開閉原則。如果你要生產的產品很多,而且是一個產品族。并且面臨不同產品族切換的情況。那么可以考慮通過抽象工廠來實現。