摘要
抽象工厂设计模式是一种创建型设计模式,旨在提供一个接口,用于创建一系列相关或依赖的对象,无需指定具体类。它通过抽象工厂、具体工厂、抽象产品和具体产品等组件构建,相比工厂方法模式,能创建一个产品族。该模式适用于多个产品需一起创建的场景,可隐藏产品细节,便于客户端使用。

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<>();
@Autowired
public 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;
@Autowired
private 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 {
@Override
public String getBizType() {
return "consumerLoan";
}
@Override
public void evaluateUserProfile(String userId) {
System.out.println("消费贷用户画像评估: " + userId);
}
@Override
public void evaluateFraud(String userId) {
System.out.println("消费贷反欺诈评估: " + userId);
}
@Override
public 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<>();
@PostConstruct
public 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 {
@Bean
public RiskRuleFactoryRegistry riskRuleFactoryRegistry() {
return new RiskRuleFactoryRegistry();
}
@Bean
public 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;
@Autowired
private 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 支持运行时加载多个实现 |