Java設計模式(二)之建立型模式:抽象工廠模式
例子背景:
隨著客戶的要求越來越高,寶馬車需要不同配置的空調和發動機等配件。於是這個工廠開始生產空調和發動機,用來組裝汽車。這時候工廠有兩個系列的產品:空調和發動機。寶馬320系列配置A型號空調和A型號發動機,寶馬230系列配置B型號空調和B型號發動機。
一、概念:
在工廠方法模式中,我們使用一個工廠建立一個產品,也就是說一個具體的工廠對應一個具體的產品。但是有時候我們需要一個工廠能夠提供多個產品物件,而不是單一的物件,這個時候我們就需要使用抽象工廠模式。
在講解抽象工廠模式之前,我們需要釐清兩個概念:
(1)產品等級結構:產品的等級結構也就是產品的繼承結構。例如一個為空調的抽象類,它有海爾空調、格力空調、美的空調等一系列的子類,那麼這個抽象類空調和他的子類就構成了一個產品等級結構。
(2)產品族:產品族是在抽象工廠模式中的。在抽象工廠模式中,產品族是指由同一個工廠生產的,位於不同產品等級結構中的一組產品。比如,海爾工廠生產海爾空調。海爾冰箱,那麼海爾空調則位於空調產品族中。
產品等級結構和產品族結構示意圖如下:
二、基本定義:
抽象工廠模式提供一個介面,用於建立相關或者依賴物件的家族,而不需要明確指定具體類。抽象工廠允許使用抽象的介面來建立一組相關的產品,而不需要關心實際產出的具體產品是什麼,這樣一來,客戶就可以從具體的產品中被解耦。
如寶馬320系列使用空調型號A和發動機型號A,而寶馬230系列使用空調型號B和發動機型號B,那麼使用抽象工廠模式,在為320系列生產相關配件時,就無需制定配件的型號,它會自動根據車型生產對應的配件型號A。
UML結構圖如下:
AbstractFactory:抽象工廠。抽象工廠定義了一個介面,所有的具體工廠都必須實現此介面,這個介面包含了一組方法用來生產產品。
ConcreteFactory:具體工廠。具體工廠是用於生產不同產品族。要建立一個產品,客戶只需要使用其中一個工廠完全不需要例項化任何產品物件。
AbstractProduct:抽象產品。這是一個產品家族,每一個具體工廠都能夠生產一整組產品。
Product:具體產品。
三、程式碼:
結合本例如下:
當每個抽象產品都有多於一個的具體子類的時候(空調有型號A和B兩種,發動機也有型號A和B兩種),工廠角色怎麼知道例項化哪一個子類呢?比如每個抽象產品角色都有兩個具體產品(產品空調有兩個具體產品空調A和空調B)。抽象工廠模式提供兩個具體工廠角色(寶馬320系列工廠和寶馬230系列工廠),分別對應於這兩個具體產品角色,每一個具體工廠角色只負責某一個產品角色的例項化。每一個具體工廠類只負責建立抽象產品的某一個具體子類的例項。
產品類:
//發動機以及型號
public interface Engine {
}
public class EngineA extends Engine{
public EngineA(){
System.out.println("製造-->EngineA");
}
}
public class EngineBextends Engine{
public EngineB(){
System.out.println("製造-->EngineB");
}
}
//空調以及型號
public interface Aircondition {
}
public class AirconditionA extends Aircondition{
public AirconditionA(){
System.out.println("製造-->AirconditionA");
}
}
public class AirconditionB extends Aircondition{
public AirconditionB(){
System.out.println("製造-->AirconditionB");
}
}
建立工廠類:
//建立工廠的介面
public interface AbstractFactory {
//製造發動機
public Engine createEngine();
//製造空調
public Aircondition createAircondition();
}
//為寶馬320系列生產配件
public class FactoryBMW320 implements AbstractFactory{
@Override
public Engine createEngine() {
return new EngineA();
}
@Override
public Aircondition createAircondition() {
return new AirconditionA();
}
}
//寶馬523系列
public class FactoryBMW523 implements AbstractFactory {
@Override
public Engine createEngine() {
return new EngineB();
}
@Override
public Aircondition createAircondition() {
return new AirconditionB();
}
}
客戶:
public class Customer {
public static void main(String[] args){
//生產寶馬320系列配件
FactoryBMW320 factoryBMW320 = new FactoryBMW320();
factoryBMW320.createEngine();
factoryBMW320.createAircondition();
//生產寶馬523系列配件
FactoryBMW523 factoryBMW523 = new FactoryBMW523();
factoryBMW320.createEngine();
factoryBMW320.createAircondition();
}
}
四、優缺點:
1、優點:
(1) 抽象工廠隔離了具體類的生成,是的客戶端不需要知道什麼被建立。所有的具體工廠都實現了抽象工廠中定義的公共介面,因此只需要改變具體工廠的例項,就可以在某種程度上改變整個軟體系統的行為。
(2)當一個產品族中的多個物件被設計成一起工作時,它能夠保證客戶端始終只使用同一個產品族中的物件。
2、缺點:
(1)新增新的行為時比較麻煩。如果需要新增一個新產品族物件時,需要更改介面及其下所有子類,這必然會帶來很大的麻煩。
五、使用場景:
(1)一個系統不應當依賴於產品類例項如何被建立、組合和表達的細節,這對於所有型別的工廠模式都是重要的。
(2)系統中有多於一個的產品族,而每次只使用其中某一產品族。
(3)屬於同一個產品族的產品將在一起使用,這一約束必須在系統的設計中體現出來。
(4)系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴於具體實現。
參考文章: