工廠方法模式
概念
是一種常用的類創建型設計模式,此模式的核心精神是封裝類中變化的部分,提取其中個性化善變的部分爲獨立類,通過依賴注入以達到解耦、複用和方便後期維護拓展的目的。
角色
- 抽象產品
工廠方法模式所創建的對象的超類型,也就是產品對象的共同父類或共同擁有的接口。- 具體產品
這個角色實現了抽象產品角色所定義的接口。某具體產品有專門的具體工廠創建,它們之間往往一一對應。- 抽象工廠
是工廠方法模式的核心,與應用程序無關。任何在模式中創建的對象的工廠類必須實現這個接口。- 具體工廠
這是實現抽象工廠接口的具體工廠類,包含與應用程序密切相關的邏輯,並且受到應用程序調用以創建產品對象
UML圖如下
簡單工廠模式的優缺點
優點
- 用工廠創建客戶所需產品,向客戶隱藏了具體是哪個產品被實例化,客戶只需關心哪個工廠創建那個產品而不需要關心創建細節
- 讓工廠自主確定創建何種產品,如何創建完全封裝在具體工廠內部
- 符合開閉原則,向系統中添加新產品只需要添加具體的工廠和產品即可
缺點
- 添加新產品需要編寫具體產品類以及與之對應的工廠類,類的個數成對增加
適合環境
- 客戶端不需要知道他所需要對象的類
- 對於某個產品,客戶端清楚地知道應該使用哪個具體工廠服務
例子
現需要一個日誌記錄器可以通過多種方式來保存日誌,例如文件系統和數據庫系統,用戶只需通過修改配置文件就可以靈活的切換日誌方式,並且在設計日誌記錄器時,開發人員系統對日誌記錄器做一系列初始化工作,並且初始化參數設置極爲複雜。
分析
我們先將實體與簡單工廠的角色一一對應
- 抽象產品: Logger
- 具體產品: DatabaseLogger,FileLogger
- 抽象工廠: LoggerFactory
- 具體工廠: DatabaseLoggerFactory,FileLoggerFactory
看不懂不要緊,我們先看UML圖,在看代碼應該就能理解了
編碼
Logger.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:02 PM 2019/7/25
* @Description: 日誌記錄器接口,充當抽象產品角色
*/
public interface Logger {
public void writeLog();
}
FileLogger.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:06 PM 2019/7/25
* @Description: 文件日誌記錄器,充當具體的產品角色
*/
public class FileLogger implements Logger {
@Override
public void writeLog() {
System.out.println("文件日誌記錄");
}
}
DatabaseLogger.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:04 PM 2019/7/25
* @Description: 數據庫日誌記錄器,充當具體產品角色
*/
public class DatabaseLogger implements Logger {
@Override
public void writeLog() {
System.out.println("數據庫日誌記錄");
}
}
LoggerFactory.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:07 PM 2019/7/25
* @Description: 日誌記錄器工廠接口,充當抽象工廠角色
*/
public interface LoggerFactory {
/**
* 抽象工廠方法
*
* @return
*/
public Logger createLogger();
}
FileLoggerFactory.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:11 PM 2019/7/25
* @Description: 文件日誌記錄器工廠類,充當具體工廠角色
*/
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
//創建文件日誌記錄器對象
Logger logger = new FileLogger();
//創建文件,代碼略
return logger;
}
}
DatabaseLoggerFactory.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:09 PM 2019/7/25
* @Description: 數據庫日誌記錄器工廠類,充當具體工廠角色
*/
public class DatabaseLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
//連接數據庫,代碼略
//創建數據庫日誌記錄器對象
Logger logger = new DatabaseLogger();
//初始化數據庫日誌記錄器,代碼略
return logger;
}
}
config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<className>cn.kevinlu98.factorymethod.DatabaseLoggerFactory</className>
</config>
XMLUtil.xml
package cn.kevinlu98.factorymethod;
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/factorymethod/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.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:12 PM 2019/7/25
* @Description: 工廠方法設計模式 客戶端測試
*/
public class Client {
public static void main(String[] args) {
// LoggerFactory factory = (LoggerFactory) XMLUtil.getBean();
LoggerFactory factory = new DatabaseLoggerFactory();
Logger logger = factory.createLogger();
logger.writeLog();
}
}
運行結果
至此,工廠方法設計模式介紹完成,希望能幫助到您