设计模式——抽象工厂设计模式(创建型)

摘要

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

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(风控规则工厂)
  • 具体工厂:ConsumerLoanFactoryCarLoanFactory
  • 客户端:风控服务,根据业务类型获取对应工厂并执行规则引擎

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+抽象工厂设计模式总结

  1. 扩展业务线:只需实现 RiskRuleFactory 接口,并在 SPI 文件里声明实现类,打包成 jar 加入项目。
  2. 动态切换业务线:修改配置 risk.control.bizType=carLoan 即可切换到车贷业务线风控。
  3. 热插拔:新的业务线可以单独打包成 jar 通过 SPI 机制自动被加载。

优点

说明

插件式扩展

新增业务线无需改动核心代码,符合开闭原则

Spring 集成

自动装配,减少手动配置

配置驱动

通过配置灵活切换业务逻辑

动态加载

SPI 支持运行时加载多个实现

博文参考

  • 3. 抽象工厂模式(Abstract Factory) — Graphic Design Patterns
  • 抽象工厂设计模式
  • 创建型 - 抽象工厂(Abstract Factory) | Java 全栈知识体系

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/85622.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Express教程【006】:使用Express写接口

文章目录 8、使用Express写接口8.1 创建API路由模块8.2 编写GET接口8.3 编写POST接口 8、使用Express写接口 8.1 创建API路由模块 1️⃣新建routes/apiRouter.js路由模块&#xff1a; /*** 路由模块*/ // 1-导入express const express require(express); // 2-创建路由对象…

【iOS(swift)笔记-14】App版本不升级时本地数据库sqlite更新逻辑二

App版本不升级时&#xff0c;又想即时更新本地数据库怎么办&#xff1f; 办法二&#xff1a;从服务器下载最新的sqlite数据替换掉本地的数据&#xff08;注意是数据不是文件&#xff09; 稍加调整&#xff0c; // &#xff01;&#xff01;&#xff01;注意&#xff01;&…

Mac电脑_钥匙串操作选项变灰的情况下如何删除?

Mac电脑_钥匙串操作选项变灰的情况下如何删除&#xff1f; 这时候 可以使用相关的终端命令进行操作。 下面附加文章《Mac电脑_钥匙串操作的终端命令》。 《Mac电脑_钥匙串操作的终端命令》 &#xff08;来源&#xff1a;百度~百度AI 发布时间&#xff1a;2025-06&#xff09;…

对接系统外部服务组件技术方案

概述 当前系统需与多个外部系统对接,然而外部系统稳定性存在不确定性。对接过程中若出现异常,需依靠双方的日志信息来定位问题,但若日志信息不够完整,会极大降低问题定位效率。此外,问题发生后,很大程度上依赖第三方的重试机制,若第三方缺乏完善的重试机制,就需要手动…

WAF绕过,网络层面后门分析,Windows/linux/数据库提权实验

一、WAF绕过文件上传漏洞 win7&#xff1a;10.0.0.168 思路&#xff1a;要想要绕过WAF&#xff0c;第一步是要根据上传的内容找出来被拦截的原因。对于文件上传有三个可以考虑的点&#xff1a;文件后缀名&#xff0c;文件内容&#xff0c;文件类型。 第二步是根据找出来的拦截原…

一文学会c++中的内存管理知识点

文章目录 c/c内存管理c语言动态内存管理c动态内存管理new/delete自定义类型妙用operator new和operator delete malloc/new&#xff0c;free/delete区别 c/c内存管理 int globalVar 1;static int staticGlobalVar 1;void Test(){static int staticVar 1;int localVar 1;in…

深入解析Linux死锁:原理、原因及解决方案

Linux死锁是系统资源管理的致命陷阱&#xff0c;平均每年导致全球数据中心约​​3.7亿小时​​的服务中断。本文深度剖析死锁形成的​​四个必要条件​​和六种典型死锁场景&#xff0c;结合Linux内核源码层级的资源管理机制&#xff0c;揭示文件系统锁、内存分配、多线程同步等…

SKUA-GOCAD入门教程-第八节 线的创建与编辑2

8.1.3根据线创建曲线 (1)从线生成线 这个命令可以将一组曲线合并为一条曲线。每个输入曲线都会成为新曲线内的一个部分。 1、选择 Curve commands > New > Curves 打开对话框。 图1 根据曲线创建曲线 在“name”框中

『uniapp』把接口的内容下载为txt本地保存 / 读取本地保存的txt文件内容(详细图文注释)

目录 预览效果思路分析downloadTxt 方法readTxt 方法 完整代码总结 欢迎关注 『uniapp』 专栏&#xff0c;持续更新中 欢迎关注 『uniapp』 专栏&#xff0c;持续更新中 预览效果 思路分析 downloadTxt 方法 该方法主要完成两个任务&#xff1a; 下载 txt 文件&#xff1a;通…

攻防世界-unseping

进入环境 在获得的场景中发现PHP代码并进行分析 编写PHP编码 得到 Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czozOiJwd2QiO319 将其传入 想执行ls&#xff0c;但是发现被过滤掉了 使用环境变量进行绕过 $a new…

IP查询与网络风险的关系

网络风险场景与IP查询的关联 网络攻击、恶意行为、数据泄露等风险事件频发&#xff0c;而IP地址作为网络设备的唯一标识&#xff0c;承载着关键线索。例如&#xff0c;在DDoS恶意行为中&#xff0c;攻击者利用大量IP地址发起流量洪泛&#xff1b;恶意行为通过变换IP地址绕过封…

pikachu通关教程-XSS

XSS XSS漏洞原理 XSS被称为跨站脚本攻击&#xff08;Cross Site Scripting&#xff09;&#xff0c;由于和层叠样式表&#xff08;Cascading Style Sheets&#xff0c;CSS&#xff09;重名&#xff0c;改为XSS。主要基于JavaScript语言进行恶意攻击&#xff0c;因为js非常灵活…

【时时三省】(C语言基础)数组作为函数参数

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 调用有参函数时&#xff0c;需要提供实参。例如sin ( x )&#xff0c;sqrt ( 2&#xff0c;0 )&#xff0c;max ( a&#xff0c;b )等。实参可以是常量、变量或表达式。数组元素的作用与变量…

硬件工程师笔记——555定时器应用Multisim电路仿真实验汇总

目录 一 555定时器基础知识 二、引脚功能 三、工作模式 1. 单稳态模式&#xff1a; 2. 双稳态模式&#xff08;需要外部电路辅助&#xff09;&#xff1a; 3. 无稳态模式&#xff08;多谐振荡器&#xff09;&#xff1a; 4. 可控脉冲宽度调制&#xff08;PWM&#xff09…

C++11特性:enum class(强枚举类型)详解

C11引入的 enum class&#xff08;强枚举类型&#xff09;解决了传统枚举的多个问题&#xff1a; 防止枚举值泄漏到外部作用域&#xff1b;禁止不同枚举间的隐式转换&#xff1b;允许指定底层数据类型优化内存&#xff1b;避免命名空间污染。 其基本语法为 enum class Name{.…

【QT】QString 与QString区别

在C中&#xff0c;QString 和 QString& 有本质区别&#xff0c;尤其是在参数传递和内存管理方面&#xff1a; 1. QString&#xff08;按值传递&#xff09; 创建副本&#xff1a;传递时会创建完整的字符串副本内存开销&#xff1a;可能涉及深拷贝&#xff08;特别是大字符…

提升四级阅读速度方法

以下是针对四级英语阅读速度提升的系统性解决方案&#xff0c;结合最新考试规律和高效训练方法&#xff0c;分五个核心模块整理&#xff1a; &#x1f680; ​​一、基础提速训练&#xff08;消除生理障碍&#xff09;​​ ​​扩大视幅范围​​ 从逐词阅读升级为 ​​意群阅读…

6.4 note

构造矩阵 class Solution { private: vector<int> empty {}; // 返回每个数字(-1)所在的序号&#xff0c;可以是行或列, 如果为空则无效 vector<int> topoSort(int k, vector<vector<int>>& conditions) { // 构建一个图…

SCSS 全面深度解析

一、SCSS 入门指南&#xff1a;为你的 CSS 工作流注入超能力 在现代 Web 开发中&#xff0c;样式表的复杂性和维护成本日益增加。为了应对这一挑战&#xff0c;CSS 预处理器应运而生&#xff0c;而 SCSS (Sassy CSS) 正是其中最流行、最强大的工具之一。本指南将带你深入了解 …

R1-Searcher++新突破!强化学习如何赋能大模型动态知识获取?

R1-Searcher新突破&#xff01;强化学习如何赋能大模型动态知识获取&#xff1f; 大语言模型&#xff08;LLM&#xff09;虽强大却易因静态知识产生幻觉&#xff0c;检索增强生成&#xff08;RAG&#xff09;技术成破局关键。本文将解读R1-Searcher框架&#xff0c;看其如何通…