抽象工廠模式是常見的建造型設計模式之一,比工廠方法模式抽象程度更高。工廠方法模式中具體工廠只生產一種具體產品,但在抽象工廠模式中,具體工廠可以生產相關的一組具體產品,這樣一組產品稱為產品族,產品族中的每一個產品分屬於某一產品繼承等級結構。
模式動機
有時候我們需要一個工廠提供多個產品對象,而不是單一一個產品對象,如一個電器設備工廠,它可以生產電視機、電冰箱、空調等設備,而不只是生成某種類型的電器。為了更清晰地理解抽象工廠模式,這里先引入兩個概念:
-
產品等級結構:產品等級結構即產品的繼承結構,如一個抽象類是電視機,其子類有海爾電視機、TCL電視機等,抽象電視機與具體品牌電視機之間構成了一個產品等級結構。
-
產品族:指由同一工廠生產的,位於不同產品等級結構中的一組產品,如海爾電器工廠生產海爾電視機、海爾電冰箱,則它們是同一產品族,各自位於不同產品等級結構。
當系統提供的工廠生產的具體產品不是一個簡單對象,而是多個位於不同產品等級結構中屬於不同類型的具體產品時需要使用抽象工廠模式。
模式定義
提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們具體的類。
模式結構
-
AbstractFacory(抽象工廠)
抽象工廠用於聲明生產抽象產品的方法,在一個抽象工廠中可以定義一組方法,每一方法對應一個產品等級結構
-
ConcreteFactory(具體工廠)
具體工廠實現抽象工廠聲明的生產抽象產品的方法,生產一組具體產品,這些產品構成一個產品族,每一個產品都位於某個產品等級結構中。
-
AbstractProduct(抽象產品)
抽象產品為每種產品聲明接口,在抽象產品中定義產品的抽象業務方法
-
ConcreteProduct(具體產品)
具體產品定義具體工廠生產的具體產品對象,實現抽象產品接口中定義的業務方法。
抽象工廠模式實例之電器工廠
-
實例說明
一個電器工廠可以產生多種類型的電器,如海爾工廠可以生產海爾電視機、海爾空調等,TCL工廠可以生產TCL電視機、TCL空調等,相同品牌的電器構成一個產品族,而相同類型電器構成一個產品等級結構。
-
實例代碼及解釋
-
抽象產品類Television
public interface Television { void play(); }
-
具體產品類HairTelevision(海爾電視機類)
public class HairTelevision implements Television { @Override public void play() { System.out.println("海爾電視機播放中......"); } }
-
具體產品類TCLTelevision(TCL電視機類)
public class TCLTelevision implements Television { @Override public void play() { System.out.println("TCL電視機播放中......."); } }
-
抽象產品類AirConditioner
public interface AirConditioner { void changeTemperature(); }
-
具體產品類HairAirConditioner(海爾空調類)
public class HairAirConditioner implements AirConditioner { @Override public void changeTemperature() { System.out.println("海爾空調溫度改變中....."); } }
-
具體產品類TCLAirConditioner(TCL空調類)
public class TCLAirConditioner implements AirConditioner { @Override public void changeTemperature() { System.out.println("TCL空調溫度改變中......"); } }
-
抽象工廠類EFactory
public interface EFactory { Television produceTelevision(); AirConditioner produceAirConditioner(); }
-
具體工廠類HairFactory(海爾工廠類)
public class HairFactory implements EFactory { @Override public Television produceTelevision() { return new HairTelevision(); } @Override public AirConditioner produceAirConditioner() { return new HairAirConditioner(); } }
-
具體工廠類TCLPFactory
public class TCLFactory implements EFactory { @Override public Television produceTelevision() { return new TCLTelevision(); } @Override public AirConditioner produceAirConditioner() { return new TCLAirConditioner(); } }
-
XML操作工具類
public class XMLUtil { public static Object getBean() throws Exception { //創建解析器工廠 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); //創建解析器 DocumentBuilder builder = builderFactory.newDocumentBuilder(); //得到document Document document = builder.parse("configPhone.xml"); //獲取包含品牌名稱的文本節點 NodeList brandNameList = document.getElementsByTagName("factoryName"); Node classNode = brandNameList.item(0).getFirstChild(); String factoryName = classNode.getNodeValue().trim(); // System.out.println(factoryName); Class c = Class.forName(factoryName); Object o = c.newInstance(); return o; } }
-
配置文件
<?xml version="1.0" encoding="UTF-8" ?> <configuration> <factoryName>HairFactory</factoryName> </configuration>
-
測試類
public class Test { public static void main(String[] args) throws Exception { EFactory factory = (EFactory) XMLUtil.getBean(); Television television = factory.produceTelevision(); television.play(); AirConditioner airConditioner = factory.produceAirConditioner(); airConditioner.changeTemperature(); } }
-
結果分析
如果在配置文件將節點中內容設置為 HairFactory,則輸出結果如下:
如果在配置文件將節點中內容設置為 TCLFactory,則輸出結果如下:
如果需要增加新品牌的電器,即增加一個新的產品族,如增加海信電視機和海信空調,則只需對應增加一個具體工廠,再將配置文件中具體工廠類名修改為新增工廠類名,原有代碼無須修改。但如果要增加新的產品,如增加新的電器產品洗衣機,抽象工廠需要聲明一個生產洗衣機的方法,所有具體工廠類都需實現該方法,將導致系統不再符合開閉原則。
-