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

news2025/7/22 16:56:34

摘要

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

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<>();

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

  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.coloradmin.cn/o/2401689.html

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

相关文章

基于LocalAI与cpolar技术协同的本地化AI模型部署与远程访问方案解析

文章目录 前言1. Docker部署2. 简单使用演示3. 安装cpolar内网穿透4. 配置公网地址5. 配置固定公网地址前言 各位极客朋友们!今天要向大家推荐一套创新性的本地部署方案——LocalAI技术架构。这款开源工具包能够将普通配置的笔记本电脑转化为具备强大算力的AI工作站,轻松实现…

霍尔效应传感器的革新突破:铟化铟晶体与结构演进驱动汽车点火系统升级

一、半导体材料革新&#xff1a;铟化铟晶体的电压放大机制 铟化铟&#xff08;InSb&#xff09;晶体因其独特的能带结构&#xff0c;成为提升霍尔电压的关键材料。相较于传统硅基材料&#xff0c;其载流子迁移率高出3-5倍&#xff0c;在相同磁场强度下可显著放大霍尔电压。其作…

无法运用pytorch环境、改环境路径、隔离环境

一.未建虚拟环境时 1.创建新项目后&#xff0c;直接运行是这样的。 2.设置中Virtualenv找不到pytorch环境&#xff1f;因为此时没有创建新虚拟环境。 3.选择conda环境&#xff08;全局环境&#xff09;时&#xff0c;是可以下载环境的。 运行结果如下&#xff1a; 是全局环境…

从0开始学vue:pnpm怎么安装

一、什么是 pnpm&#xff1f; pnpm&#xff08;Performant npm&#xff09;是新一代 JavaScript 包管理器&#xff0c;优势包括&#xff1a; 节省磁盘空间&#xff1a;通过硬链接和符号链接实现高效存储安装速度更快&#xff1a;比 npm/yarn 快 2-3 倍内置工作区支持&#xf…

Python 网络编程 -- WebSocket编程

作者主要是为了用python构建实时网络通信程序。 概念性的东西越简单越好理解,因此,下面我从晚上摘抄的概念 我的理解。 什么是网络通信? 更确切地说&#xff0c;网络通信是两台计算机上的两个进程之间的通信。比如&#xff0c;浏览器进程和新浪服务器上的某个Web服务进程在通…

边缘计算应用实践心得

当数据中心的光纤开始承载不了爆炸式增长的物联网数据流时&#xff0c;边缘计算就像毛细血管般渗透进现代数字肌理的末梢。这种将算力下沉到数据源头的技术范式&#xff0c;本质上是对传统云计算中心化架构的叛逆与补充——在智能制造车间里&#xff0c;实时质检算法直接在工业…

EXCEL如何快速批量给两字姓名中间加空格

EXCEL如何快速批量给姓名中间加空格 优点&#xff1a;不会导致排版混乱 缺点&#xff1a;无法输出在原有单元格上&#xff0c;若需要保留原始数据&#xff0c;可将公式结果复制后“选择性粘贴为值” 使用场景&#xff1a;在EXCEL中想要快速批量给两字姓名中间加入空格使姓名对…

Jenkins | Linux环境部署Jenkins与部署java项目

1. 部署jenkins 1.1 下载war包 依赖环境 jdk 11 下载地址: https://www.jenkins.io/ 依赖环境 1.2 启动服务 启动命令 需要注意使用jdk11以上的版本 直接启动 # httpPort 指定端口 #-Xms2048m -Xmx4096m 指定java 堆内存初始大小 与最大大小 /usr/java/jdk17/bin/java…

react私有样式处理

react私有样式处理 Nav.jsx Menu.jsx vue中通过scoped来实现样式私有化。加上scoped&#xff0c;就属于当前组件的私有样式。 给视图中的元素都加了一个属性data-v-xxx&#xff0c;然后给这些样式都加上属性选择器。&#xff08;deep就是不加属性也不加属性选择器&#xff09; …

UDP/TCP协议全解

目录 一. UDP协议 1.UDP协议概念 2.UDP数据报格式 3.UDP协议差错控制 二. TCP协议 1.TCP协议概念 2.三次握手与四次挥手 3.TCP报文段格式&#xff08;重点&#xff09; 4.流量控制 5.拥塞控制 一. UDP协议 1.UDP协议概念 当应用层的进程1要向进程2传输报文&#xff…

Duix.HeyGem:以“离线+开源”重构数字人创作生态

在AI技术快速演进的今天,虚拟数字人正从高成本、高门槛的专业领域走向大众化应用。Duix.HeyGem 数字人项目正是这一趋势下的杰出代表。该项目由一支拥有七年AI研发经验的团队打造,通过放弃传统3D建模路径,转向真人视频驱动的AI训练模型,成功实现了低成本、高质量、本地化的…

ubuntu22.04安装megaton

前置 sudo apt-get install git cmake ninja-build generate-ninja安装devkitPro https://blog.csdn.net/qq_39942341/article/details/148388639?spm1001.2014.3001.5502 安装cargo https://blog.csdn.net/qq_39942341/article/details/148387783?spm1001.2014.3001.5501 …

Windows应用-GUID工具

下载本应用 我们在DirectShow和媒体基础程序的调试中&#xff0c;将会遇到大量的GUID&#xff0c;调试窗口大部分情况下只给出GUID字符串&#xff0c;此GUID代表什么&#xff0c;我们无从得知。这时&#xff0c;就需要此“GUID工具”&#xff0c;将GUID字符串翻译为GUID定义&am…

vue+element-ui一个页面有多个子组件组成。子组件里面有各种表单,实现点击enter实现跳转到下一个表单元素的功能。

一个父组件里面是有各个子组件的form表单组成的。 我想实现点击enter。焦点直接跳转到下一个表单元素。 父组件就是由各个子组件构成 子组件就像下图一样的都有个el-form的表单。 enterToTab.js let enterToTab {}; (function() {// 返回随机数enterToTab.addEnterListener …

Vehicle HAL(5)--vhal 实现设置属性的流程

目录 1. ard11 vhal 设置属性的时序图 CarService > vhal > CarService 2. EmulatedVehicleHal::set(xxx) 的实现 本文介绍ard11的vhal属性设置流程图。 1. ard11 vhal 设置属性的时序图 CarService > vhal > CarService 2. EmulatedVehicleHal::set(xxx) 的实现…

WebRTC中的几个Rtp*Sender

一、问题&#xff1a; webrtc当中有几个比较相似的类&#xff0c;看着都是发送RTP数据包的&#xff0c;分别是&#xff1a;RtpPacketToSend 和RtpSenderVideo还有RtpVideoSender以及RTPSender&#xff0c;这说明什么呢&#xff1f;首先&#xff0c;说明我会很多连词&#xff0…

代码随想录算法训练营第十一天 | 150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素、栈与队列总结

150. 逆波兰表达式求值--后缀表达式 力扣题目链接(opens new window) 根据 逆波兰表示法&#xff0c;求表达式的值。 有效的运算符包括 , - , * , / 。每个运算对象可以是整数&#xff0c;也可以是另一个逆波兰表达式。 说明&#xff1a; 整数除法只保留整数部分。 给…

IDEA202403 设置主题和护眼色

文章目录 背景一、设置主题二、设置背景豆沙绿三、设置控制台颜色 背景 在用IDEA进行开发时&#xff0c;长时间对着屏幕&#xff0c;不费眼是及其重要 一、设置主题 默认的主题是 Dark 暗黑&#xff0c;可更改为其他&#xff0c;如Light 高亮 位置&#xff1a;编辑栏【files…

无人机螺旋桨平衡方法详解

螺旋桨平衡对于优化无人机性能、可靠性和使用寿命至关重要。不平衡的螺旋桨会产生过度振动&#xff0c;导致推力效率降低、噪音增大&#xff0c;并加速轴承和传感器的磨损。 螺旋桨平衡可通过三种方式实现&#xff1a;静态平衡、动态平衡和气动平衡。 静态与动态平衡是通过在…

基于51单片机的车内防窒息检测报警系统

目录 具体实现功能 设计介绍 资料内容 全部内容 资料获取 具体实现功能 具体实现功能&#xff1a; &#xff08;1&#xff09;检测车内温度及二氧化碳浓度并用lcd1602实时显示。 &#xff08;2&#xff09;当人体红外传感器检测到车内有人&#xff0c;且温度或二氧化碳浓度…