抽象工廠模式
概念
抽象工廠模式是所有形態的工廠模式中最爲抽象和最具一般性的一種形態。抽象工廠模式是指當有多個抽象角色時,使用的一種工廠模式。抽象工廠模式可以向客戶端提供一個接口,使客戶端在不必指定產品的具體的情況下,創建多個產品族中的產品對象
兩個重要概念
產品等級結構
產品的等級結構即產品的繼承結構,例如一個抽象類是電冰箱,其子類包括海爾電冰箱,海信電冰箱,TCL電冰箱等,抽象冰箱與具體品牌的冰箱構成了產品等級結構
產品族
同一個工廠生產的位於不同產品等級結構中的一組產品,例如海爾電器生產的海爾電視機,海爾電冰箱,海爾空調等,這些海爾產品構成了一個產品族
角色
- 抽象工廠: 它聲明瞭一組用於創建一族產品的方法,每一個方法對於一種產品
- 具體工廠: 他實現了在抽象工廠中什麼的創建產品的方法,生成一組具體產品,這些產品構成了一個產品族
- 抽象產品: 它爲每種產品什麼接口,即產品等級結構中的抽象接口
- 具體產品: 定義具體工廠生產的具體產品對象,實現抽象產品中聲明的業務接口
UML圖如下
簡單工廠模式的優缺點
優點
- 隔離了具體類的生產,更換一個具體的工廠變得相對容易
- 保證客戶端始終只使用同一個產品族中的對象
- 增加新產品族方便,符合開閉原則
缺點
新增產品等級結構麻煩,需要對原有系統做大量的修改,甚至需要改抽象層代碼
補充
前面一直說開閉原則,到底什麼是開閉原則
開閉原則要求系統對擴展開放,對修改關閉。
適合環境
- 一個系統不應當依賴於產品類的實例如何被創建等細節,無需關心對象創建過程
- 系統中有多個產品族,每次只使用其中一個產品族
- 產品等級結構穩定,不會向系統中新增心得產品等級結構或者刪除已有的產品等級結構
例子
現需要開發一套皮膚庫,用戶可以通過菜單選擇不同皮膚,不同的皮膚提供不同視覺效果的按鈕,文本框,組合框等元素。例如春天(Spring)風格的淺綠色按鈕、文本框。組合框,而夏天(Summer)風格的淡藍色按鈕、文本框、組合框等
分析
我們先將實體與簡單工廠的角色一一對應
- 抽象工廠: SkinFactory
- 具體工廠: SpringSkinFactory、SummerSkinFactory
- 抽象產品: Button、TextField、ComboBox
- 具體產品: SpringButton、SpringTextField、SpringComboBox、SummerButton、SummerTextField、SummerComboBox
看不懂不要緊,我們先看UML圖,在看代碼應該就能理解了
編碼
Button.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:20 PM 2019/7/26
* @Description: 按鈕接口,充當抽象產品
*/
public interface Button {
void dispaly();
}
SpringButton.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:21 PM 2019/7/26
* @Description: spring按鈕類,充當具體的產品
*/
public class SpringButton implements Button {
@Override
public void dispaly() {
System.out.println("顯示淺綠色按鈕");
}
}
SummerButton.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:22 PM 2019/7/26
* @Description: summer按鈕類,充當具體產品
*/
public class SummerButton implements Button {
@Override
public void dispaly() {
System.out.println("顯示淺藍色按鈕");
}
}
ComboBox.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:25 PM 2019/7/26
* @Description: 組合框接口,充當抽象產品
*/
public interface ComboBox {
void display();
}
SpringComboBox.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:26 PM 2019/7/26
* @Description: spring類型組合框,充當具體產品
*/
public class SpringComboBox implements ComboBox {
@Override
public void display() {
System.out.println("顯示綠色邊框組合框");
}
}
SummerComboBox.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:26 PM 2019/7/26
* @Description: summer組合框類,充當具體產品
*/
public class SummerComboBox implements ComboBox{
@Override
public void display() {
System.out.println("顯示藍色邊框組合框");
}
}
TextField.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:23 PM 2019/7/26
* @Description: 文本框接口,充當抽象產品
*/
public interface TextField {
void display();
}
SpringTextField.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:23 PM 2019/7/26
* @Description: spring文本框類,充當具體產品
*/
public class SpringTextField implements TextField {
@Override
public void display() {
System.out.println("顯示綠色邊框文本框");
}
}
SummerTextField.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:24 PM 2019/7/26
* @Description: summer文本框類,充當具體產品
*/
public class SummerTextField implements TextField {
@Override
public void display() {
System.out.println("顯示藍色邊框文本框");
}
}
SkinFactory.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:27 PM 2019/7/26
* @Description: 界面皮膚工廠接口,充當抽象工廠
*/
public interface SkinFactory {
Button createButton();
TextField createTextField();
ComboBox createComboBox();
}
SpringSkinFactory.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:28 PM 2019/7/26
* @Description: spring皮膚工廠,充當具體工廠
*/
public class SpringSkinFactory implements SkinFactory {
@Override
public Button createButton() {
return new SpringButton();
}
@Override
public TextField createTextField() {
return new SpringTextField();
}
@Override
public ComboBox createComboBox() {
return new SpringComboBox();
}
}
SummerSkinFactory.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:30 PM 2019/7/26
* @Description: summer皮膚工廠,充當具體工廠
*/
public class SummerSkinFactory implements SkinFactory {
@Override
public Button createButton() {
return new SummerButton();
}
@Override
public TextField createTextField() {
return new SummerTextField();
}
@Override
public ComboBox createComboBox() {
return new SummerComboBox();
}
}
config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<className>cn.kevinlu98.abstractfactory.SummerSkinFactory</className>
</config>
XMLUtil.java
package cn.kevinlu98.abstractfactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
/**
* @Author: Kevin·Lu
* @Date: 9:17 PM 2019/7/25
* @Description: 讀取xml文件中的字符串參數
*/
public class XMLUtil {
public static Object getBean() {
try {
//創建dom文檔對象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File("src/cn/kevinlu98/abstractfactory/config.xml"));
//獲取包含類名的文本節點
NodeList nl = document.getElementsByTagName("className");
Node classNode = nl.item(0).getFirstChild();
String name = classNode.getNodeValue();
//通過類名生成實例對象並將其返回
Class c = Class.forName(name);
Object object = c.newInstance();
return object;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Client.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:33 PM 2019/7/26
* @Description: 抽象工廠模式,客戶端測試類
*/
public class Client {
public static void main(String[] args) {
SkinFactory factory = (SkinFactory) XMLUtil.getBean();
Button button = factory.createButton();
TextField textField = factory.createTextField();
ComboBox comboBox = factory.createComboBox();
button.dispaly();
textField.display();
comboBox.display();
}
}
運行結果
至此,工廠方法設計模式介紹完成,希望能幫助到您