摘要
抽象工廠設計模式是一種創建型設計模式,旨在提供一個接口,用于創建一系列相關或依賴的對象,無需指定具體類。它通過抽象工廠、具體工廠、抽象產品和具體產品等組件構建,相比工廠方法模式,能創建一個產品族。該模式適用于多個產品需一起創建的場景,可隱藏產品細節,便于客戶端使用。
1. 抽象工廠設計模式定義
抽象工廠模式是創建型設計模式的一種,它提供一個接口,用于創建一系列相關或相互依賴的對象,而無需指定它們的具體類。就像一個“超級工廠”,里面包含多個子工廠,用于生產同一產品族中的各種產品。你不關心產品的具體實現,只關心工廠能提供什么樣的系列產品。
核心要點:
維度 | 描述 |
意圖 | 為創建相關對象的家族提供一個統一的接口 |
解決問題 | 解決“多個產品之間需要一起創建”的問題 |
與工廠方法對比 | 工廠方法是一個產品一個工廠;抽象工廠是一個產品族一個工廠 |
隱藏細節 | 客戶端不需要知道具體產品類,只通過抽象接口使用 |
2. 抽象工廠設計模式結構
2.1. 抽象工廠設計模式類圖
- AbstractFactory:抽象工廠
- ConcreteFactory:具體工廠
- AbstractProduct:抽象產品
- Product:具體產品
2.2. 抽象工廠設計模式時序圖
3. 抽象工廠設計模式實現方式
抽象工廠模式的實現,主要通過一組產品接口 + 一個抽象工廠接口 + 多個具體工廠實現類來構建。下面是完整的標準實現方式。
3.1. 🧱 實現步驟(Java 示例)
3.1.1. 定義抽象產品接口
// 抽象產品 A
public interface Button {void click();
}// 抽象產品 B
public interface TextField {void input(String text);
}
3.1.2. 定義具體產品類
// Windows 系列產品
public class WindowsButton implements Button {public void click() {System.out.println("Windows 按鈕點擊");}
}public class WindowsTextField implements TextField {public void input(String text) {System.out.println("Windows 輸入: " + text);}
}// Mac 系列產品
public class MacButton implements Button {public void click() {System.out.println("Mac 按鈕點擊");}
}public class MacTextField implements TextField {public void input(String text) {System.out.println("Mac 輸入: " + text);}
}
3.1.3. 定義抽象工廠接口
public interface GUIFactory {Button createButton();TextField createTextField();
}
3.1.4. 實現具體工廠類
public class WindowsFactory implements GUIFactory {public Button createButton() {return new WindowsButton();}public TextField createTextField() {return new WindowsTextField();}
}public class MacFactory implements GUIFactory {public Button createButton() {return new MacButton();}public TextField createTextField() {return new MacTextField();}
}
3.1.5. 客戶端使用示例
public class Application {public static void main(String[] args) {// 可通過配置文件或環境變量來控制GUIFactory factory = new WindowsFactory();// GUIFactory factory = new MacFactory();Button button = factory.createButton();TextField textField = factory.createTextField();button.click();textField.input("Hello World!");}
}
3.2. ? 抽象工廠模式特點
特點 | 描述 |
解耦 | 客戶端不需要了解產品的具體類 |
易于擴展 | 可以輕松新增新的產品族,只需添加一個新的工廠類 |
成本 | 新增產品種類時,需要修改所有工廠類(違背開閉原則) |
應用場景 | 多產品族、產品組合固定、創建邏輯復雜的場景 |
4. 抽象工廠設計模式適合場景
抽象工廠是一種創建型設計模式,適用于需要一組相關或互相依賴的對象的場景。
4.1. ? 適合使用抽象工廠模式的場景
場景 | 說明 |
產品族固定,且產品之間有依賴關系 | 比如 GUI 界面中,按鈕、文本框等控件需風格統一(如 Windows、Mac)。 |
系統需要獨立于產品創建邏輯 | 客戶端無需關心產品如何創建,只關注使用接口。 |
需要保證產品之間的一致性(風格/協議/行為) | 比如同一品牌的組件應配套使用,避免混搭出錯。 |
系統有多個產品族,但每次只使用其中一個 | 比如數據庫連接池的不同廠商實現(Druid、HikariCP)。 |
適合用于“橫向擴展”產品族,而不是“縱向擴展”產品種類 | 可以增加新的平臺或風格,但不易增加產品接口。 |
4.2. ? 不適合使用抽象工廠模式的場景
場景 | 原因 |
? 只需要創建一種對象,不是一個產品族 | 比如只創建不同類型的日志對象,用簡單工廠或策略更合適。 |
? 頻繁增加新的產品(產品等級結構) | 每新增一個產品類型(接口),所有具體工廠都要修改,違背“開閉原則”。 |
? 產品之間無依賴、不要求一致性 | 沒有必要引入抽象工廠,使用簡單工廠或直接實例化即可。 |
? 產品構造非常簡單,擴展性需求低 | 抽象工廠的結構較復雜,維護成本較高,可能得不償失。 |
? 僅用于單一系統或開發周期很短的小項目 | 引入抽象工廠會增加架構復雜度。 |
4.3. 📌 抽象工廠設計模式總結
項目 | 抽象工廠適用 | 不適用 |
是否一組產品族 | ? 是 | ? 否 |
是否要求統一風格 | ? 是 | ? 否 |
是否頻繁新增產品接口 | ? 否 | ? 是 |
是否希望屏蔽實例化邏輯 | ? 是 | ? 否 |
5. 抽象工廠設計模式實戰示例
在金融風控系統中,不同的業務線(如消費貸、車貸、現金貸等)往往使用不同的風控規則引擎或評分模型。抽象工廠模式在這里可以用于隔離不同業務線的策略實現,提升系統的可擴展性和解耦能力。
5.1. ? 多業務線風控規則工廠示例:
系統支持多個業務線,每個業務線都有自己的一套風控規則引擎(如用戶畫像評分、反欺詐規則、額度評估等),需要統一接口、按業務線隔離實現。
5.2. 🧱 抽象設計結構
- 抽象產品:
RiskRuleEngine
(風控規則引擎) - 抽象工廠:
RiskRuleFactory
(風控規則工廠) - 具體工廠:
ConsumerLoanFactory
、CarLoanFactory
等 - 客戶端:風控服務,根據業務類型獲取對應工廠并執行規則引擎
5.3. 🧩 代碼結構
5.3.1. 抽象產品接口
public interface RiskRuleEngine {void evaluate(String userId);
}
5.3.2. 抽象工廠接口
public interface RiskRuleFactory {RiskRuleEngine createUserProfileEngine();RiskRuleEngine createFraudEngine();RiskRuleEngine createCreditLimitEngine();
}
5.3.3. 具體產品實現(以消費貸為例)
@Component
public class ConsumerUserProfileEngine implements RiskRuleEngine {public void evaluate(String userId) {System.out.println("消費貸 - 用戶畫像評估:" + userId);}
}@Component
public class ConsumerFraudEngine implements RiskRuleEngine {public void evaluate(String userId) {System.out.println("消費貸 - 反欺詐規則評估:" + userId);}
}@Component
public class ConsumerCreditLimitEngine implements RiskRuleEngine {public void evaluate(String userId) {System.out.println("消費貸 - 授信額度評估:" + userId);}
}
5.3.4. 消費貸工廠實現
@Component("consumerLoanFactory")
public class ConsumerLoanFactory implements RiskRuleFactory {@Autowired private ConsumerUserProfileEngine userProfileEngine;@Autowired private ConsumerFraudEngine fraudEngine;@Autowired private ConsumerCreditLimitEngine creditLimitEngine;public RiskRuleEngine createUserProfileEngine() {return userProfileEngine;}public RiskRuleEngine createFraudEngine() {return fraudEngine;}public RiskRuleEngine createCreditLimitEngine() {return creditLimitEngine;}
}
5.3.5. 客戶端服務按業務線執行風控評估
@Service
public class RiskControlService {@Autowired@Qualifier("consumerLoanFactory") // 或通過配置中心動態選擇工廠private RiskRuleFactory riskRuleFactory;public void doRiskEvaluate(String userId) {riskRuleFactory.createUserProfileEngine().evaluate(userId);riskRuleFactory.createFraudEngine().evaluate(userId);riskRuleFactory.createCreditLimitEngine().evaluate(userId);}
}
5.4. ? 如果要支持動態業務線切換(如配置中心配置當前業務)
你可以將所有工廠注冊進一個 Map:
@Component
public class RiskRuleFactoryRegistry {private final Map<String, RiskRuleFactory> factoryMap = new HashMap<>();@Autowiredpublic RiskRuleFactoryRegistry(List<RiskRuleFactory> factories) {for (RiskRuleFactory factory : factories) {factoryMap.put(factory.getClass().getSimpleName().replace("Factory", "").toLowerCase(), factory);}}public RiskRuleFactory getFactory(String bizType) {return factoryMap.get(bizType.toLowerCase());}
}
5.5. ? 使用配置中心動態切換工廠
@Service
public class DynamicRiskControlService {@Value("${biz.line.type:consumerLoan}")private String bizType;@Autowiredprivate RiskRuleFactoryRegistry registry;public void doEvaluate(String userId) {RiskRuleFactory factory = registry.getFactory(bizType);factory.createUserProfileEngine().evaluate(userId);factory.createFraudEngine().evaluate(userId);factory.createCreditLimitEngine().evaluate(userId);}
}
5.6. ? 抽象工廠涉及面模式總結
優勢 | 描述 |
模塊隔離 | 不同業務線的規則邏輯完全隔離,避免混亂 |
易于擴展 | 新業務線只需實現一套工廠和引擎,不影響老業務 |
支持插件化 | 工廠可結合 SPI 動態加載 |
配置驅動 | 支持配置中心動態切換業務邏輯 |
6. 抽象工廠設計模式思考
6.1. 引入SPI 加載抽象工廠、或者結合 Spring Boot Starter 自動注冊不同業務線的風控策略示例
6.1.1. 需求回顧
- 多業務線(消費貸、車貸等)各自實現一套
RiskRuleFactory
。 - 通過 SPI 機制實現工廠插件化,支持 jar 擴展、熱插拔。
- Spring Boot 啟動時自動掃描 SPI 實現,注冊到工廠注冊中心。
- 支持根據配置動態切換當前業務線風控工廠。
6.1.2. 項目結構示例
risk-control-spi/├─ META-INF/services/com.example.risk.spi.RiskRuleFactory├─ com/example/risk/spi/│ ├─ RiskRuleFactory.java // SPI接口│ ├─ ConsumerLoanFactory.java // 業務線1實現│ ├─ CarLoanFactory.java // 業務線2實現├─ com/example/risk/spring/│ ├─ RiskRuleFactoryRegistry.java│ ├─ RiskControlAutoConfiguration.java│ ├─ DynamicRiskControlService.java
6.1.3. 示例代碼
SPI接口定義(RiskRuleFactory
)
package com.example.risk.spi;public interface RiskRuleFactory {// 返回業務線標識,如 "consumerLoan"String getBizType(); void evaluateUserProfile(String userId);void evaluateFraud(String userId);void evaluateCreditLimit(String userId);
}
SPI實現(以消費貸為例)
package com.example.risk.spi;public class ConsumerLoanFactory implements RiskRuleFactory {@Overridepublic String getBizType() {return "consumerLoan";}@Overridepublic void evaluateUserProfile(String userId) {System.out.println("消費貸用戶畫像評估: " + userId);}@Overridepublic void evaluateFraud(String userId) {System.out.println("消費貸反欺詐評估: " + userId);}@Overridepublic void evaluateCreditLimit(String userId) {System.out.println("消費貸授信額度評估: " + userId);}
}
同理實現 CarLoanFactory
等其他業務線工廠。
SPI配置文件:文件路徑:src/main/resources/META-INF/services/com.example.risk.spi.RiskRuleFactory
內容(每行一個實現類全限定名):
com.example.risk.spi.ConsumerLoanFactory
com.example.risk.spi.CarLoanFactory
工廠注冊中心(Spring Bean)
package com.example.risk.spring;import com.example.risk.spi.RiskRuleFactory;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.util.*;@Component
public class RiskRuleFactoryRegistry {private final Map<String, RiskRuleFactory> factoryMap = new HashMap<>();@PostConstructpublic void init() {ServiceLoader<RiskRuleFactory> loader = ServiceLoader.load(RiskRuleFactory.class);for (RiskRuleFactory factory : loader) {factoryMap.put(factory.getBizType(), factory);System.out.println("加載風控工廠:" + factory.getBizType());}}public RiskRuleFactory getFactory(String bizType) {RiskRuleFactory factory = factoryMap.get(bizType);if (factory == null) {throw new IllegalArgumentException("不支持的業務線: " + bizType);}return factory;}
}
Spring Boot 自動配置類
package com.example.risk.spring;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@ConditionalOnProperty(prefix = "risk.control", name = "enabled", havingValue = "true", matchIfMissing = true)
public class RiskControlAutoConfiguration {@Beanpublic RiskRuleFactoryRegistry riskRuleFactoryRegistry() {return new RiskRuleFactoryRegistry();}@Beanpublic DynamicRiskControlService dynamicRiskControlService() {return new DynamicRiskControlService();}
}
動態風控服務
package com.example.risk.spring;import com.example.risk.spi.RiskRuleFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;@Service
public class DynamicRiskControlService {@Value("${risk.control.bizType:consumerLoan}")private String bizType;@Autowiredprivate RiskRuleFactoryRegistry registry;public void doEvaluate(String userId) {RiskRuleFactory factory = registry.getFactory(bizType);factory.evaluateUserProfile(userId);factory.evaluateFraud(userId);factory.evaluateCreditLimit(userId);}
}
6.1.4. SPI+抽象工廠設計模式總結
- 擴展業務線:只需實現
RiskRuleFactory
接口,并在 SPI 文件里聲明實現類,打包成 jar 加入項目。 - 動態切換業務線:修改配置
risk.control.bizType=carLoan
即可切換到車貸業務線風控。 - 熱插拔:新的業務線可以單獨打包成 jar 通過 SPI 機制自動被加載。
優點 | 說明 |
插件式擴展 | 新增業務線無需改動核心代碼,符合開閉原則 |
Spring 集成 | 自動裝配,減少手動配置 |
配置驅動 | 通過配置靈活切換業務邏輯 |
動態加載 | SPI 支持運行時加載多個實現 |
博文參考
- 3. 抽象工廠模式(Abstract Factory) — Graphic Design Patterns
- 抽象工廠設計模式
- 創建型 - 抽象工廠(Abstract Factory) | Java 全棧知識體系