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

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

背景

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

思路

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

方案一:状态模式

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

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

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

方案二:策略模式

  • 策略模式
        众所周知的策略模式通常都有这样的类图:
    p_w_picpath工具

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

  • 扩展
        策略模式下,如何增长新的状态、新的迁移操做呢?
        因为策略模式仅仅定义了“状态迁移”动做,所以,不管是增长新的状态、仍是增长新的迁移操做,都只须要增长对应的子类便可。spa

对比

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

相关文章
相关标签/搜索