1. 引言
在现代软件开发中,设计模式不仅提高了代码的可读性和可维护性,还帮助开发者在面对复杂问题时找到优雅的解决方案。策略模式是这些模式之一,它尤其擅长处理需要在运行时根据条件选择不同算法或流程的情况。
策略模式的定义和作用:
策略模式(Strategy Pattern)属于行为型设计模式,它定义了算法族,分别封装起来,让它们之间可以互相替换。该模式让算法的变化独立于使用算法的客户。在这个模式中,每一个算法都被封装在具有共同接口的独立的类中,从而使得它们可以互换。策略模式的核心思想是定义一系列算法,将每一个算法封装起来,并使它们可以相互替换,使算法可以在不影响客户端的情况下发生变化。
在OA系统中的应用背景:
在办公自动化(OA)系统中,策略模式的应用尤为显著。OA系统通常涉及多种复杂的业务流程,如请假审批、报销流程、出差申请等。每种流程可能需要不同的处理逻辑和审批步骤。使用策略模式,我们可以为每种业务流程创建具体的处理策略(Handler),而服务层(Service)只需要调用这些策略,而不必关心具体的实现细节。这种模式的应用使得新增或修改业务流程时只需增加或修改具体的策略类,而不需要改动服务层代码,极大地提高了系统的可扩展性和可维护性。
通过将不同的业务流程逻辑封装在独立的策略类中,OA系统的设计更加模块化,每个模块都可以独立变化而互不影响,从而应对不断变化的业务需求,提供灵活、可配置的工作流处理能力。
2. OA系统中策略模式的总体设计
基本调用链的逻辑图片如下,以一个简单的创建一条新的审批记录为例子。过程详细描述了如何从controller层接受请求,到最后完成数据库插入的完整流程:
-
Controller:
-
职责:处理用户界面层的交互,接收来自源于教师,学生,管理员各种用户的请求并调用下一级服务处理这些请求。
-
说明:标注了@RestController,能够接收用户操作,如表单提交,审批推进,审批流程发起。
-
-
OfficeAutomationService:
-
职责:作为服务层组件,负责处理业务逻辑,这里特别是处理审批记录的创建。
-
说明:它调用
OfficeAutomationHandlerType
来确定具体的处理策略,并基于策略执行审批记录的创建。
-
-
OfficeAutomationHandlerType:
-
职责:负责匹配并确定具体的
OfficeAutomationHandler
实例。 -
说明:一个枚举类,根据审批类型ID从数据库中查询并匹配相应的处理器。
-
-
Database (DB):
-
职责:存储所有涉及的OA数据,包括审批类型和审批记录等。
-
说明:在这个上下文中,数据库响应类型ID的查询,返回相应的审批类型数据对象。
-
-
OfficeAutomationHandler:
-
职责:处理具体的审批逻辑。
-
说明:这是一个抽象基类或接口,具体的子类实现将根据审批类型执行实际的审批逻辑。
-
交互流程
-
Controller 接收到创建审批记录的请求,并调用 OfficeAutomationService。
-
OfficeAutomationService 询问 OfficeAutomationHandlerType 以匹配和获取正确的审批类型。
-
OfficeAutomationHandlerType 查询 Database 获取审批类型信息。
-
如果类型存在,Database 返回类型数据给 OfficeAutomationHandlerType,然后传回给 OfficeAutomationService。
-
OfficeAutomationService 根据得到的类型信息获取或创建相应子类的 OfficeAutomationHandler。
-
OfficeAutomationService 使用 OfficeAutomationHandler 子类的处理具体的审批记录创建逻辑。
-
最后,OfficeAutomationService 将结果返回给 Controller。
设计考量
这种设计提供了良好的解耦和灵活性,允许系统通过更换不同的 OfficeAutomationHandler 实现来适应不同类型的审批流程。每种处理器都可以专注于特定类型的审批逻辑,而服务层管理这些处理器并提供统一的接口给上层控制器。
3. OfficeAutomationService类的设计
OfficeAutomationService类的作用
OfficeAutomationHandler 是一个抽象类,设计为本OA系统中处理不同审批流程的核心组件。该类定义了一系列抽象方法和具体方法,使得具体的审批流程可以根据不同的业务需求进行定制和扩展。
OfficeAutomationService 是OA系统中的一个关键服务层组件,它承担着多个重要职责:
-
无关于具体OA类型的OA记录查询:
-
在Service层中设置了一些和后续的审批流程的经过无关的方法,比如允许管理员或者学生去查询当前他们有哪些正在流程中的OA进程。这些方法和具体的某一种OA没有关系,只需要输入学生当前的id和对应的描述,就能够查询到记录。
-
比如像这两个方法
-
-
作为Controller和Handler层的中间层
-
获得Handler进行执行特定的OA逻辑的流程:
最关键的设计思想!!!在这里通过策略模式,根据ApprovalTypeId的数值去获得对应的Handler,从而执行对应Handler的具体OA流程。
-
参数校验:在Controller接受前端发来的请求,在继承了抽象类的Handler的子类之中实现具体的OA审批执行流程,而把一些复杂的参数检验,比如说不为空,参数非法这些错误直接抛出到上一层。
-
-
Handler的管理和获取:
-
策略实例的管理:管理不同类型的审批处理策略实例,如请假、报销等,每种策略均对应一个具体的处理类(Handler)。
-
动态策略获取:根据审批类型动态获取相应的处理器,使得新增审批类型或修改现有逻辑时,只需添加或修改相应的处理器实现。
-
维护Map对象
在 OfficeAutomationService 中,一个重要的成员变量是用于存储处理器实例的Map:
private final Map<OfficeAutomationHandlerType, OfficeAutomationHandler> officeAutomationHandlers;
这个Map对象的键是审批类型,值是对应的处理器实例。在构造方法执行的时候,全部从数据库中获取对应的OA流程,直接加入当前的Map中。
构造方法的设计
构造方法的设计使得 OfficeAutomationService 在实例化时就配置好所有需要的处理器。这通过依赖注入(DI)完成,Spring框架允许自动注入所有实现了特定接口的Bean。这里的设计思想是通过Spring自动注入所有OfficeAutomationHandler
实例,并将它们放入Map中管理:
public OfficeAutomationService(List<OfficeAutomationHandler> officeAutomationHandlersList, List<MongoRepository> mongoRepositories) { // 将处理器列表转换为Map,使用处理器类型作为键 this.officeAutomationHandlers = officeAutomationHandlersList.stream() .collect(Collectors.toMap(OfficeAutomationHandler::supportType, handler -> handler)); }
通过stream和Collectors.toMap收集Handler:
supportType()
方法在每个OfficeAutomationHandler
实现中定义,返回该处理器支持的审批类型。
如何升级呢?
在原始的 OfficeAutomationService
类中,审批处理器(handlers)的初始化是在构造方法中进行的,这种方式在依赖注入的环境中可能导致问题。由于构造方法是在Spring容器注入依赖之前调用的,如果构造方法内需要依赖于被注入的组件进行逻辑操作,就可能因为组件尚未完全初始化而导致空指针异常或者配置错误。
使用 @PostConstruct
注解可以确保在所有必要的依赖注入完成之后再执行初始化逻辑。
下面是如何使用@PostConstruct
来升级OfficeAutomationService
类的初始化:
1. 定义@PostConstruct
方法
在OfficeAutomationService
类中,添加一个@PostConstruct
注解的方法,该方法在Spring容器实例化并注入所有依赖后调用。
import javax.annotation.PostConstruct; @Service public class OfficeAutomationService { private Map<OfficeAutomationHandlerType, OfficeAutomationHandler> officeAutomationHandlers; @Autowired private List<OfficeAutomationHandler> officeAutomationHandlersList; @PostConstruct public void init() { officeAutomationHandlers = officeAutomationHandlersList.stream() .collect(Collectors.toMap(OfficeAutomationHandler::supportType, handler -> handler)); // 日志记录或其他初始化后操作 System.out.println("OfficeAutomationService initialized with " + officeAutomationHandlers.size() + " handlers."); } // 现有的方法和逻辑... }
2. 使用@PostConstruct
确保正确的配置
通过在@PostConstruct
注解的方法中配置officeAutomationHandlers
Map,你确保了只有在所有OfficeAutomationHandler
beans都已注入后,才进行Map的构建。这避免了在构造函数中使用依赖注入可能遇到的顺序和完整性问题。
3. 验证配置
在@PostConstruct
方法中,可以添加额外的检查或日志记录,以验证审批处理器是否已正确配置:
@PostConstruct public void validateHandlers() { if (officeAutomationHandlers.isEmpty()) { throw new IllegalStateException("No approval handlers are configured."); } officeAutomationHandlers.forEach((type, handler) -> System.out.println("Configured handler for type: " + type)); }
4. OfficeAutomationHandler的方法设计
对于OfficeAutomationHandler
类中的方法,按照其功能和用途,我们可以将这些方法分为以下几个类别:
1. 检查参数
这类方法主要用于验证传入数据的合法性,确保在进一步处理前,所有必要的条件都被满足。
-
check(ApprovalStepRecordPO)
-
描述:验证审批步骤记录的参数是否合法。
-
2. 审批流程
这类方法涉及到审批流程的启动和管理,用于控制整个审批过程的流程和状态。
-
createApprovalRecord(ApprovalRecordPO)
-
描述:创建审批记录,启动审批流程。
-
-
process(ApprovalStepRecordPO)
-
描述:处理具体的审批步骤,根据当前审批结果决定后续操作。
-
-
afterApproval(ApprovalRecordPO, ApprovalStepRecordPO)
-
描述:审批流程完成后执行的操作,例如审批成功或失败后的业务逻辑。
-
3. 当前审批步结果处理
这类方法用于根据当前审批步骤的结果执行相应的逻辑,如成功、失败或转移。
-
success(Long, Long, Date)
-
描述:处理审批成功的逻辑,可能涉及到流程的推进或结束。
-
-
failed(Long, Date)
-
描述:处理审批失败的逻辑,通常需要进行某种形式的错误处理或回退操作。
-
-
transfer(Long, Date, Long)
-
描述:在需要时将审批流程转移至下一步骤。
-
4. 表单处理
这类方法与具体的文档或表单操作相关,包括创建、删除、选择和更新文档。
-
selectDocument(String)
-
描述:根据文档ID选择文档。
-
-
deleteDocument(String)
-
描述:根据文档ID删除文档。
-
-
insertDocument(Map<String, Object>)
-
描述:插入新文档,并返回文档ID。
-
-
updateById(Map<String, Object>, String)
-
描述:根据文档ID更新文档信息。
-
通过这样的分类,OfficeAutomationHandler
类中的方法更加清晰地映射到不同的功能需求上,使得维护和扩展功能变得更为直接和简便。这种组织方法也有助于新开发者更快地理解系统的工作流程和逻辑结构。
调度逻辑
具体方法执行和流程,将在下一章给大家手把手debug看看一个流程是怎么样的!这里不再详细展开,先把基本逻辑梳理完!
5. OfficeAutomationHandler中依赖的注入
OfficeAutomationHandler
是一个高度集成了多个Service实例的核心实例,多个服务和工具类通过依赖注入的方式被整合,以支持各种审批流程的处理。
使用的技术和注入方式
@Resource protected ApprovalRecordService approvalRecordService; @Resource protected ApprovalStepRecordService approvalStepRecordService; @Resource protected ApprovalStepService approvalStepService; @Resource protected MongoTemplate mongoTemplate; @Resource protected PlatformUserService platformUserService; @Resource protected CollegeAdminInformationService collegeAdminInformationService; @Resource protected SystemMessageService systemMessageService;
各依赖的作用描述
-
ApprovalRecordService
-
作用:管理审批记录的业务逻辑,如创建、查询和更新审批记录。这是处理审批流程中的关键组件,确保审批记录的状态被正确管理和维护。
-
-
ApprovalStepRecordService
-
作用:专注于审批步骤记录的管理,包括记录每一步的审批结果和状态。这有助于追踪整个审批过程的进展,并为后续步骤提供必要的上下文。
-
-
ApprovalStepService
-
作用:处理与审批步骤定义相关的操作,如获取特定审批流程的步骤配置。这对于执行流程控制和条件逻辑判断至关重要。
-
-
MongoTemplate
-
作用:提供与MongoDB数据库交互的操作模板,支持复杂的查询、插入、更新和删除操作。在文档驱动的数据模型中,这是执行非关系型数据库操作的核心工具。
-
-
PlatformUserService
-
作用:管理平台用户的服务,包括用户信息的查询和验证。在审批流程中,经常需要验证用户的身份和角色,以决定其对某一审批步骤的访问权限。
-
-
CollegeAdminInformationService
-
作用:提供对学院管理员信息的访问,这在处理涉及特定学院的审批时尤为重要,如学院级别的财务审批或事件审批。
-
-
SystemMessageService
-
作用:负责生成和发送系统消息,如审批通知和结果反馈。这确保了审批流程的透明度和参与者的即时更新。
-
6. 设计的灵活性与扩展性
本节探讨如何通过扩展OfficeAutomationHandler
抽象类来支持新的审批类型,从而提升系统的可维护性和未来的业务适应性。
当前继承子类的名称及其业务功能
在OfficeAutomationHandler
体系结构中,不同的业务功能通过各自的子类实现具体化。
-
StudentSuspensionOfStudyHandler:处理学生休学的审批。
-
SchoolInTransferMajorHandler:处理校内转专业的审批。
-
SchoolOutTransferMajorHandler:处理校外转专业的审批。
这些类继承自OfficeAutomationHandler
,各自实现了特定审批类型所需的逻辑。
支持新的审批类型
要在OA系统中引入新的审批类型,可以按照以下步骤进行:
-
数据库审批类型的添加
新的审批类型首先需要在数据库中定义。这涉及到
approval_type
表的扩展,通过以下SQL语句添加新的审批类型:
INSERT INTO approval_type (name, description) VALUES ('new-approval-type', '新审批类型描述');
-
创建新的Handler类
对于每一种新的审批类型,创建一个对应的Handler类,这个类继承自
OfficeAutomationHandler
。例如,为"新审批类型"创建一个新的Handler:public class NewApprovalTypeHandler extends OfficeAutomationHandler { @Override public boolean check(ApprovalStepRecordPO stepRecord) { // 实现检查逻辑 } @Override public void afterProcess(ApprovalStepRecordPO stepRecord, ApprovalRecordPO record) { // 实现审批后处理逻辑 } // 其他必要的方法实现... }
-
在
OfficeAutomationHandlerType
枚举中新增条目在
OfficeAutomationHandlerType
枚举中添加一个新的条目,与数据库中的类型名称保持一致:如果不一致,那么就无法匹配!!!
NEW_APPROVAL_TYPE("new-approval-type", "新审批类型"),
-
重写抽象类中的方法
在新创建的Handler类中,重写
OfficeAutomationHandler
抽象类中定义的所有抽象方法,确保新的审批类型具备完整的功能实现。
7. 总结
在本集中,我们深入探讨了OfficeAutomationHandler
和OfficeAutomationService
类的设计与实现,这些是构建一个弹性和可扩展的办公自动化系统的关键组件。我们讨论了如何通过抽象类OfficeAutomationHandler
来处理不同审批流程的具体化,以及如何通过服务类OfficeAutomationService
来管理这些流程,确保系统的高效运作。
回顾上集内容
在之前的内容中,我们详细介绍了OfficeAutomationHandler
抽象类的结构和主要方法,这些方法包括审批记录的检查、处理、以及审批步骤的管理。每个方法都针对特定的审批流程提供了必要的逻辑实现。此外,我们还探讨了如何通过继承这个抽象类来创建具体的处理器类,以支持不同类型的审批需求。
为下集做铺垫
在下一集中,我们将具体深入到OfficeAutomationHandler
的实现策略中。每个策略类都针对特定的业务场景提供了定制的审批流程处理方法。我们将展示这些策略类如何实现OfficeAutomationHandler
中定义的抽象方法,以及它们是如何与整体系统交互,处理实际的审批任务。
具体来说,我们将探讨以下几个方面:
-
实现细节:详细介绍一个核心类,学生退学Handler类,展示它的具体实现逻辑。
-
业务逻辑的集成:说明这些策略类是如何与数据库、消息系统等其他系统组件协同工作,以确保审批流程的顺畅和数据的一致性。
通过下集的内容,开发者将能够更好地理解如何构建和维护一个功能强大、易于扩展的办公自动化系统,同时确保系统能够灵活应对不断变化的业务需求。这不仅有助于提升系统的性能和用户满意度,也将深化读者对企业级应用开发实践的理解。