在软件开发中,设计模式是解决特定问题的通用方案,而工厂模式与策略模式的结合使用,能在特定业务场景下发挥强大的威力。本文将基于新增题目(题目类型有单选、多选、判断、解答)这一业务场景,详细阐述如何运用 Java 中的工厂 + 策略设计模式来实现。

一、设计模式简介

  1. 工厂模式 工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。其核心思想是定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪一个类,工厂模式使一个类的实例化延迟到其子类。

  2. 策略模式 策略模式是一种行为型设计模式,它定义了算法家族,分别封装起来,让它们之间可以互相替换。此模式让算法的变化独立于使用算法的客户。

二、业务场景分析

        在对数智教育社区进行重构时,针对其中的刷题模块开展深入分析。该模块涵盖单选、多选、判断、解答等多种题目类型,仅以新增操作为例,不同题型有着截然不同的逻辑要求:单选题需保障选项唯一正确,多选题允许存在多个正确选项,判断题聚焦于对错判定,解答题则着重于答案的详细评估。倘若舍弃合适设计模式,单纯运用 if - else 进行编码,那么随着题目类型不断丰富以及业务逻辑愈发复杂,代码将陷入难以维护与拓展的困境。然而,借助策略模式与工厂模式联袂运用,成功封装内部实现细节,对外呈现统一调用接口,在大幅削减 if/else 业务代码量的同时,令代码的维护与扩展过程变得更为轻松便捷。

三、实战教程

3.1 定义枚举

/*** 题目类型枚举* 1单选 2多选 3判断 4简答*/
@Getter
public enum SubjectInfoTypeEnum {RADIO(1,"单选"),MULTIPLE(2,"多选"),JUDGE(3,"判断"),BRIEF(4,"简答"),;public int code;public String desc;SubjectInfoTypeEnum(int code, String desc){this.code = code;this.desc = desc;}/*** 根据code值获取枚举对象* @param codeVal code值* @return*/public static SubjectInfoTypeEnum getByCode(int codeVal){for(SubjectInfoTypeEnum resultCodeEnum : SubjectInfoTypeEnum.values()){if(resultCodeEnum.code == codeVal){return resultCodeEnum;}}return null;}}

3.2 定义策略接口

        创建一个策略接口 SubjectTypeHandler,该接口旨在定义所有题目类型通用的操作规范。具体而言,它声明了用于识别枚举身份的方法以及执行实际题目插入操作的方法,以此确保不同类型题目在处理时能够遵循统一的标准和流程,便于后续的扩展与维护。

public interface SubjectTypeHandler {/*** 枚举身份的识别*/SubjectInfoTypeEnum getHandlerType();/*** 实际的题目的插入*/void add(SubjectInfoBO subjectInfoBO);}

3.3 实现具体策略

针对每种题目类型,实现具体的策略类,这些类实现了 SubjectTypeHandler接口,并提供了与特定题型相关的具体实现。

3.3.1 单选题策略

/*** 单选题目的策略类*/
@Component
public class RadioTypeHandler implements SubjectTypeHandler {@Resourceprivate SubjectRadioService subjectRadioService;@Overridepublic SubjectInfoTypeEnum getHandlerType() {return SubjectInfoTypeEnum.RADIO;}@Overridepublic void add(SubjectInfoBO subjectInfoBO) {//单选题目的插入List<SubjectRadio> subjectRadioList = new LinkedList<>();subjectInfoBO.getOptionList().forEach(option -> {SubjectRadio subjectRadio = RadioSubjectConverter.INSTANCE.convertBoToEntity(option);subjectRadio.setSubjectId(subjectInfoBO.getId());subjectRadio.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());subjectRadioList.add(subjectRadio);});subjectRadioService.batchInsert(subjectRadioList);}}

3.3.2 多选题策略

/*** 多选题目的策略类*/
@Component
public class MultipleTypeHandler implements SubjectTypeHandler{@Resourceprivate SubjectMultipleService subjectMultipleService;@Overridepublic SubjectInfoTypeEnum getHandlerType() {return SubjectInfoTypeEnum.MULTIPLE;}@Overridepublic void add(SubjectInfoBO subjectInfoBO) {//多选题目的插入List<SubjectMultiple> subjectMultipleList = new LinkedList<>();subjectInfoBO.getOptionList().forEach(option -> {SubjectMultiple subjectMultiple = MultipleSubjectConverter.INSTANCE.convertBoToEntity(option);subjectMultiple.setSubjectId(subjectInfoBO.getId());subjectMultiple.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());subjectMultipleList.add(subjectMultiple);});subjectMultipleService.batchInsert(subjectMultipleList);}}

3.3.3 判断题策略

/*** 判断题目的策略类*/
@Component
public class JudgeTypeHandler implements SubjectTypeHandler{@Resourceprivate SubjectJudgeService subjectJudgeService;@Overridepublic SubjectInfoTypeEnum getHandlerType() {return SubjectInfoTypeEnum.JUDGE;}@Overridepublic void add(SubjectInfoBO subjectInfoBO) {//判断题目的插入SubjectJudge subjectJudge = new SubjectJudge();SubjectAnswerBO subjectAnswerBO = subjectInfoBO.getOptionList().get(0);subjectJudge.setSubjectId(subjectInfoBO.getId());subjectJudge.setIsCorrect(subjectAnswerBO.getIsCorrect());subjectJudge.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());subjectJudgeService.insert(subjectJudge);}}

3.3.4 简答题策略

/*** 简答题目的策略类*/
@Component
public class BriefTypeHandler implements SubjectTypeHandler{@Resourceprivate SubjectBriefService subjectBriefService;@Overridepublic SubjectInfoTypeEnum getHandlerType() {return SubjectInfoTypeEnum.BRIEF;}@Overridepublic void add(SubjectInfoBO subjectInfoBO) {SubjectBrief subjectBrief = BriefSubjectConverter.INSTANCE.convertBoToEntity(subjectInfoBO);subjectBrief.setSubjectId(subjectInfoBO.getId().intValue());subjectBrief.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());subjectBriefService.insert(subjectBrief);}}

3.4创建工厂类

        创建了一个工厂类SubjectTypeHandlerFactory,根据不同的题目类型提供相应的处理类实例。它利用 Spring 的依赖注入功能自动收集所有实现了 SubjectTypeHandler 接口的类实例,并在初始化时将它们注册到一个映射表中。当需要处理某个题目时,可以通过题目类型代码获取到对应的处理类实例,从而实现根据不同题目类型进行不同处理的逻辑。

/*** 题目类型工厂*/
@Component
public class SubjectTypeHandlerFactory implements InitializingBean {@Resourceprivate List<SubjectTypeHandler> subjectTypeHandlerList;private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>();public SubjectTypeHandler getHandler(int subjectType) {SubjectInfoTypeEnum subjectInfoTypeEnum = SubjectInfoTypeEnum.getByCode(subjectType);return handlerMap.get(subjectInfoTypeEnum);}@Overridepublic void afterPropertiesSet() throws Exception {for (SubjectTypeHandler subjectTypeHandler : subjectTypeHandlerList) {handlerMap.put(subjectTypeHandler.getHandlerType(), subjectTypeHandler);}}}

这段代码是一个 Spring 组件类,实现了 InitializingBean 接口,主要作用是作为题目类型处理的工厂类,负责根据不同的题目类型提供对应的处理类实例。以下是代码的详细解释:

注解与类定义

  • @Component:标记该类为 Spring 的一个组件,使 Spring 容器能够自动检测并管理这个类的实例,无需手动创建对象。

  • public class SubjectTypeHandlerFactory implements InitializingBean:定义了一个名为 SubjectTypeHandlerFactory 的公共类,实现了 InitializingBean 接口,以便在 Bean 初始化完成后执行特定的初始化逻辑。

属性

  • @Resource:这是一个依赖注入注解,用于自动注入 subjectTypeHandlerList 属性的值。Spring 容器会查找所有实现了 SubjectTypeHandler 接口的 Bean,并将它们收集到这个列表中。

  • private List<SubjectTypeHandler> subjectTypeHandlerList:这是一个私有列表属性,用于存储所有可用的题目类型处理类实例。

  • private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>():这是一个私有映射表,用于将题目类型枚举(SubjectInfoTypeEnum)与对应的处理类实例(SubjectTypeHandler)关联起来,方便后续根据题目类型快速获取相应的处理类。

方法

  • public SubjectTypeHandler getHandler(int subjectType):这是一个公共方法,用于根据给定的题目类型代码(subjectType)获取对应的处理类实例。它首先调用 SubjectInfoTypeEnum.getByCode(subjectType) 方法将整数类型的题目类型代码转换为对应的枚举类型实例(SubjectInfoTypeEnum),然后从 handlerMap 映射表中查找并返回对应的处理类实例。

  • @Override public void afterPropertiesSet() throws Exception:这个方法覆写了 InitializingBean 接口的 afterPropertiesSet 方法。当 Spring 容器初始化完该 Bean 的所有属性后,会自动调用这个方法。在这个方法中,它遍历 subjectTypeHandlerList 列表中的每个处理类实例,并通过调用 subjectTypeHandler.getHandlerType() 方法获取该处理类实例所对应的题目类型枚举,然后将这个枚举和实例作为键值对存入 handlerMap 映射表中,从而完成处理类实例与题目类型的关联。

3.5使用示例

在实际业务场景中,当需要新增题目时,可以根据题目类型获取相应的策略对象,并调用其方法完成题目相关操作。

public void add(SubjectInfoBO subjectInfoBO) {//新增题目主表信息SubjectInfo subjectInfo = SubjectInfoConverter.INSTANCE.convertBoToInfo(subjectInfoBO);subjectInfoService.insert(subjectInfo);//根据不同策略,新增对应的题目信息SubjectTypeHandler subjectTypeHandler = subjectTypeHandlerFactory.getHandler(subjectInfo.getSubjectType());subjectTypeHandler.add(subjectInfoBO);}

四、总结

通过在题目系统中应用 Java 的工厂 + 策略设计模式,我们实现了以下优点:

  1. 良好的扩展性 :当需要新增题目类型时,只需添加新的策略类和在工厂类中进行简单扩展,无需修改现有代码的主体结构。

  2. 代码复用性高 :将每种题型的逻辑封装在独立的策略类中,便于代码的复用和维护。

  3. 清晰的责任划分 :工厂类负责创建对象,策略类负责定义算法,使得系统职责明确,易于理解和测试。

这种设计模式的组合使用为解决类似具有多种类型变体且每种类型有不同行为逻辑的业务场景提供了一种优雅、灵活且可维护的解决方案。

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

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

相关文章

Nuxt3中使用 Ant-Design-Vue 的BackTop 组件实现自动返回页面顶部

在现代 Web 应用中&#xff0c;提供一个方便用户返回页面顶部的功能是非常重要的。Ant Design Vue 提供了 BackTop 组件&#xff0c;可以轻松实现这一功能。本文将详细介绍如何在 Nuxt 3 项目中使用 <a-back-top/> 组件&#xff0c;并通过按需引入的方式加载组件及其样式…

在统信UOS(Linux)中构建SQLite3桌面应用笔记

目录 1 下载lazarus 2 下载sqlite3源码编译生成库文件 3 新建项目 4 设置并编译 一次极简单的测试&#xff0c;记录一下。 操作系统&#xff1a;统信UOS&#xff0c; 内核&#xff1a;4.19.0-arm64-desktop 处理器&#xff1a;D3000 整个流程难点是生成so库文件并正确加…

Host ‘db01‘ is not allowed to connect to this MariaDB server 怎么解决?

出现错误 ERROR 1130 (HY000): Host db01 is not allowed to connect to this MariaDB server&#xff0c;表示当前用户 test 没有足够的权限从主机 db01 连接到 MariaDB 服务器。以下是逐步解决方案&#xff1a; 1. 检查用户权限 登录 MariaDB 服务器&#xff08;需本地或通过…

打造高可用的大模型推理服务:基于 DeepSeek 的企业级部署实战

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、引言&#xff1a;从“能部署”到“可用、好用、能扩展” 近年来&#xff0c;随着 DeepSeek、Qwen、Yi 等开源大模型的持续发…

Spring Boot 使用 ElasticSearch

第一步&#xff0c;开启本地的 ElasticSearch 启动 elasticSearch.bat npm run start (head 插件) 第二步&#xff0c;在 Spring Boot 项目中引入依赖 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-hig…

软件开发的“中庸之道”:因势而为,心中有数

【软件工程】软件开发的“中庸之道”&#xff1a;因势而为&#xff0c;心中有数 在软件开发的方法论讨论中&#xff0c;我们常常陷入非此即彼的二元对立&#xff1a;要么追求极致的规范化和流程化&#xff0c;严格遵循软件工程的各项标准&#xff1b;要么完全摒弃方法论&#x…

Go和Elixir极简HTTP服务对比

Go 和 Elixir 都是我非常喜欢的编程语言&#xff0c;这次来对比下它们实现一个原生极简 HTTP 服务的过程。 Go 语言标准库自带了网络服务库&#xff0c;只需要简单几行代码就可以实现一个网络服务&#xff0c;这也是一开始它吸引我的一个方面。而 Elixir 标准库本身没有网络服…

为何要学习Objective-C?从环境搭建开始

目录 前言 Swift时代为何还要学Objective-C&#xff1f; 开发环境搭建 1. 安装Xcode 2. 创建第一个Command Line Tool项目 初识Objective-C代码 编写"Hello, Objective-C!" 编译运行程序 为什么Objective-C中的NSLog和NSString前面都有"NS"前缀&a…

ubuntu18.04安装 gcc 9以及2019版本tbb

一、安装gcc 9 ubuntu18.04默认是用的gcc7.5 sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt update sudo apt-get install gcc-9 g-9 下面是配置优先用哪个版本的gcc和g &#xff0c;后面带的值越大越优先用谁&#xff0c;并且配置完全局生效不仅仅是在当…

JdbcUtils的三个版本以及sql注入问题

JDBC的工具类 1.0版本 JDBC的工具类 2.0版本&#xff08;智能一些&#xff09;&#xff0c;编写properties属性文件&#xff0c;程序就可以读取属性文件 JDBC的工具类 3.0版本&#xff0c;加入连接池对象 我们封装jdbc工具类是为了减少代码重复&#xff0c;方便开发&#xff0…

AS32系列MCU芯片I2C模块性能解析与调试

国科安芯推出的AS32X601内置的I2C模块提供了符合工业标准的两线串行制接口&#xff0c;可用于MCU和外部IIC设备的通讯。IIC总线使用两条串行线&#xff1a;串行数据线SDA和串行时钟线SCL。 IIC接口模块实现了IIC协议的标准模式和快速模式&#xff0c;支持多主机IIC总线架构。其…

钉钉小程序开发实战:打造一个简约风格的登录页面

在上一篇文章中&#xff0c;我们已经介绍了如何搭建钉钉小程序的基础环境&#xff0c;并完成了项目的初始化配置。本文将继续深入&#xff0c;手把手带你实现一个简约风格的登录页面&#xff0c;这是大多数企业级应用不可或缺的一部分。 钉钉小程序基于前端 Web 技术栈&#x…

论文研读2-1:多GNSS双历元纯相位定位-模型建立与误差分析

后续文章: 论文研读2-2&#xff1a;多GNSS双历元纯相位定位-固定模糊度精度增益 论文研读2-3&#xff1a;多GNSS双历元纯相位定位-定位精度分析 仅相位定位中的模糊度解算问题 在卫星导航定位中&#xff0c;载波相位测量是实现高精度定位的基础&#xff0c;但如果仅使用相位测…

Python----OpenCV(图像増强——图像平滑、均值滤波、高斯滤波、中值滤波、双边滤波)

Python----计算机视觉处理&#xff08;Opencv&#xff1a;图像噪点消除&#xff1a;滤波算法&#xff0c;噪点消除&#xff09; 一、图像平滑 图像平滑处理&#xff08;Smoothing Images&#xff09;&#xff0c;也称为图像模糊处理、图像滤波&#xff08;Images Filtering&am…

笔记:使用EasyExcel导入csv文件出现编码问题,导致导入数据全为null的解决方法

笔记&#xff1a;使用EasyExcel导入csv文件出现编码问题&#xff0c;导致导入数据全为null的解决方法 通常情况下&#xff0c;我们使用excel导入&#xff0c;但是部分情况下或者领导要求&#xff0c;我们需要使用csv导入文件&#xff0c;但是csv文件模板下载之后会变成系统当前…

NL2SQL(Natural Language to SQL)优化之道:提升准确率与复杂查询能力

自然语言 → SQL 的转译&#xff08;NL2SQL&#xff09;技术&#xff0c;是让非技术用户与数据库“对话”的桥梁。而在实际应用中&#xff0c;我们不仅需要“能转”&#xff0c;更要“转得准、转得全、转得快”。 一、什么是 NL2SQL&#xff1f; NL2SQL&#xff08;Natural La…

java中map的循环方式

什么是Map集合&#xff1f; Map是Java中的一个接口&#xff0c;它用于存储键-值对&#xff0c;并且键和值都可以是任意对象。它是Java集合框架中的一部分&#xff0c;并提供了一些方法来操作和访问Map中的元素。 Map中的每个键都是唯一的&#xff0c;这意味着不能使用相同的键…

python学习笔记(深度学习)

文章目录 1、概述2、学习内容2.1、pytorch 常见语法2.1.1、sum2.1.2、广播机制2.1.3、张量2.1.4、DataLoader 2.2、普通语法2.2.1、迭代器 1、概述 本篇博客用来记录&#xff0c;在深度学习过程中&#xff0c;常用的 python 语法内容 2、学习内容 2.1、pytorch 常见语法 2.…

力扣网C语言编程题:搜索二维矩阵(右上角->左下角解法)

一. 简介 上一篇文章关于"在二维数组中查找某个元素"的问题&#xff0c;提供了两种解题思路&#xff0c;文章如下&#xff1a; 力扣网C语言编程题&#xff1a;搜索二维矩阵的普通解法与二分查找法-CSDN博客 本文提供第三种解题思路&#xff1a;从左下角->右上角…

AI大模型流式输出,OkHttp Log拦截打印方案

背景&#xff1a; 使用okhttp框架进行网络访问时&#xff0c;一般会使用 HttpLoggingInterceptor 打印请求和响应的log。在使用okhttp访问AI大模型时&#xff0c;如果选择流式输出&#xff0c;那么响应的body数据使用的SSE技术&#xff0c;服务异步发送大模型生成的增量token&…