状态与策略——审批操作的两种方案

简介:

 审批操作是ERP或OA系统中必不可少的功能之一。这里介绍两种我设计的用于审批操作的方案,并借此就“状态模式”与“策略模式”提出一点自己的理解。
    别问我为什么不使用工作流引擎等工具来实现审批功能。做第一版方案时,我孤陋寡闻得并不知道有这个东西。后来引入工作流框架会导致学习曲线骤然上扬,不太划算。

背景

    背景无需过多介绍,不外乎有一些数据/任务/请求,需要由领导们点一下头或者按钮。

思路

    由于孤陋寡闻,在得到需求之后,我第一反应不是“工作流”,而是“状态机”。它从“提交”状态开始,流经“已初审”“已终审”或者“初审驳回”“终审驳回”等状态,进入终态。
    这个状态机如下图所示:
image
    当然,状态机中状态的名称、状态间的流转,是与业务需求紧密相关的。例如,有些业务会要求在“已终审”状态下执行“驳回”操作后进入“终审驳回”状态,而有些则要求返回“已初审”状态。不过万变不离其宗,种种流程最终都能归纳到“状态机”中来。
    在这个思路下,我用了两种不同的设计模式来实现需求——状态模式和策略模式,它们都很好的完成了任务。需要多说一句的是,这是两个不同系统下独立的两次实现,而不是一个系统中的“原始版”和“改进版”。因而,两个方案之间并没有非常显著的优劣对比,本文的重点也不是二者的“优劣”对比。

方案一:状态模式

  • 状态模式
        首先来回顾一下我们常说的状态模式。简便起见,这里只提供类图。
        image
        其中的核心是“状态”接口。这个接口中有N个方法,对应的是状态机中的N个状态。每个方法负责从当前状态迁移到另一个状态上——一般是别的状态,也可以仍然是当前状态。
        每个具体的状态都继承自这个接口,并在实现类中封装自己所需要的数据、重写自己的状态迁移操作。

  • 我的方案
        在我的设计方案中,类图则是这个样子的:
    image
        与“教科书”上的类图相似的,是“状态”接口(Examiner),以及各个实际状态所对应的子类。
        与之不同的是,虽然我的状态机中有五个状态,但是由于每个状态最多都只有两个状态迁移操作(通过,或者驳回),因此,状态接口中我只定义了两个方法。
        还有一点不同在于,我在Examiner接口下,加了一个默认的实现类(ExaminerAsDefault)。这个类实际上什么都不做,每个方法都直接抛出UnSupportedOperationException。这个类的作用是简化子类,使得每个子类只需要重写自己关心的方法,而不需要重写无关方法。当然,Java 8为接口引入的默认方法,可以实现同样的功能,这是后话。此外,由于业务需求中每次只做一步状态迁移,因此Examiner接口不需要再返回自己。还有一点不同的是,这个方案中,状态迁移操作与状态数据被拆开了——迁移操作由Examiner定义,状态数据则用Dto来封装。

  • 扩展
        当出现新的状态、或者新的迁移操作怎么办呢?
        出现新的状态时,创建一个新的“状态”子类,并实现对应的“状态迁移”方法就行了。出现新的迁移操作时则更简单,只需要做第二步就可以了。

方案二:策略模式

  • 策略模式
        众所周知的策略模式一般都有这样的类图:
    image

  • 我的方案
        在我的设计方案中,类图则是这样的:
        image
        可以说这是一个“标准”的策略模式类图。接口定义从一个状态到另一个状态的迁移动作,不同的子类用不同的“策略”去实现它——例如从“已提交”到“已初审”,或者从“已初审”到“初审驳回”,等等。
        状态相关的数据,仍然由单独的Dto来保存和传递。

  • 扩展
        策略模式下,如何增加新的状态、新的迁移操作呢?
        由于策略模式仅仅定义了“状态迁移”动作,因此,无论是增加新的状态、还是增加新的迁移操作,都只需要增加对应的子类即可。

对比

    我并不喜欢比较不同设计模式之间的区别。但这里仍可以多说几句。
    用状态模式实现状态机,大概是一个最直观、最容易想到的设计。但是,标准的状态模式将状态数据也封装到状态类中。这使得这个类无法用单例实现。另外,由于状态接口中,对应每一个状态都有一个方法,这可能会使得部分子类非常的大。
    用策略模式实现状态机,与状态机思想是有冲突的。状态机是以“状态”为本,状态迁移操作为辅;而策略模式却专注于状态迁移操作,“状态”的概念淡化得几乎消失了。此外,与状态模式中的“超级类”相反,策略模式可能导致“类爆炸”。
    两种模式之间的分界线,也许只是概念上的“以状态为本”或“以操作为本”。就实践上来说,像我的方案中那样,将状态模式中的数据与操作拆分开,那么整个方案与策略模式其实相去无几。
    这是我不喜欢比较不同设计模式之间区别的原因。由于设计模式的变化、组合非常多,很多时候不同设计模式之间的界限仅仅存在于概念上、思想上,而不在实践中。费尽心思去分析“如何区分23种设计模式”,只在学习阶段有一点意义。我们更应该关注设计模式适用的业务场景、业务问题,以及如何实现它们。
    毕竟,科学可以满足于“认识世界”,技术必须要以“改造世界”为目标。



本文转自 斯然在天边 51CTO博客,原文链接:http://blog.51cto.com/winters1224/1959649,如需转载请自行联系原作者

相关文章
|
5月前
修正flowable的发起流程中根据用户信息流转不同的流程
修正flowable的发起流程中根据用户信息流转不同的流程
46 0
|
2月前
|
消息中间件 SQL DataWorks
DataWorks产品使用合集之节点冻结后还是发送基线告警,该如何解决
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
DataWorks产品使用合集之节点冻结后还是发送基线告警,该如何解决
|
4月前
|
数据采集 DataWorks 监控
DataWorks产品使用合集之如何配置周期任务(如工作流任务或调度任务)依赖于数据质量规则校验结果
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
64 0
|
5月前
|
搜索推荐
基于jeecgboot的flowabale流程节点动态设置审批人的实现
基于jeecgboot的flowabale流程节点动态设置审批人的实现
414 1
|
5月前
|
运维 安全 数据安全/隐私保护
工单系统大揭秘!选择工单系统需注意的关键因素!
这篇内容介绍了工单系统的种类和选择指南。主要类型包括IT工单系统、客户服务工单管理系统、设备维护工单管理系统和全渠道工单系统。选择合适的工单系统需考虑功能需求、企业预算、易用性、系统稳定性、售后服务和技术安全。推荐了Zoho Desk作为好用的工单系统选项,它提供专业服务和免费试用。
91 1
|
5月前
|
消息中间件 架构师 NoSQL
以架构师的视角,深入剖析如何设计订单超时自动取消的功能
我们在美团 APP 下单,假如没有立即支付,进入订单详情会显示倒计时,如果超过支付时间,订单就会被自动取消。 这篇文章,笔者想以架构师的视角,深入剖析如何设计订单超时自动取消的功能。
以架构师的视角,深入剖析如何设计订单超时自动取消的功能
如何进行需求评审后续跟踪和更新?附模板
如何进行需求评审后续跟踪和更新?附模板
124 0
|
XML 数据格式
如何使用流程 中的 DataObject 并为流程设置租户
如何使用流程 中的 DataObject 并为流程设置租户
|
程序员 测试技术 数据库
实战! 项目单据确认状态未更新排查
实战! 项目单据确认状态未更新排查
|
前端开发
前端工作小结81-状态管理里面取值
前端工作小结81-状态管理里面取值
80 0
前端工作小结81-状态管理里面取值
下一篇
无影云桌面