业务行为的分析和设计

       Author:Anders小明

        复杂业务行为通常看作是复杂规则与流程的集合。解决的基本方法依赖基本的思考方式:分解结构。
        分解的第一要素是:面向对象——内聚。通常面向对象理论会告诉我们设计的设计原则是:这个对象是什么。这样的做法对于Domain Model或者比较适合,但对应于Service或者Application层的对象并不合适。这一类对象在需求的上的描述最典型是过程式!过程式描述的最大特点是告诉我们怎么做,当我们应用面向对象设计时,相对于怎么做,我们要关心的是需求做什么。
        1.1 分解行为的是所有工作的第一步:
        分解的过程(手段),可以简单说有两个层次:
        第一层:把逻辑分解到不同继承体系的对象上;
        第二层:把逻辑分解到同一继承体系的对象的不同抽象层次上。
        两个层次(手段)的内在的理论是:做什么其实是一种行为抽象,而正如我们所知的,抽象是有层次和排列的。第一层分解在于解决顶层抽象,而第二层就解决其下层的抽象,如此反复,就可以完成整个逻辑抽象的排列。
        不过,有时我宁愿用另外一种更实战的说法来解释这样的做法:利用面向对象方法,关注于做什么来确定抽象模型,而把怎么做分解为抽象模型的派生类型。
        无论是做什么,还是怎么做,需要注意的一点是:在知识级上隐式概念的印射,在操作级上有其投影。
接下来我们面临其它一些技术问题。
        1.2 确定逻辑的组合操作关系
        在分解行为的过程中,我们先分解出了不同的对象体系,在知识级别(分析层次)上看,工作已经完成,不过在操作级别(设计层次)上看,我们还需要解决一个问题。
        不同的对象体系在系统中,根据场景,表现为两种角色:调用者和被调用者。由于被调用者的派生体系(不同的怎么做),调用者面临着一个选择,选择一个或者一组合适的被调用对象。
        如何选择有两种方式:设计时(部署时)和运行时确定。
        设计时(部署时)很简单,在程序中写上特定派生类型,基本算是hardcode。通常发生在调用方其对象体系的叶子节点直接调用被调用方的叶子节点。此时,调用者是被动选择,交给所有的被调用者(通常是叶子节点),每个被调用者采取合适逻辑操作组合。
        另一种是运行时,是调用者主动选择(通过一个工厂),根据一定规则,判断选取合适的一个或者一组action执行。通常利用外部如数据库,或者工厂+反射,利用对应被调用者的Specification来确定。
        主动选择可以是简单的if…else…来完成,当选择的影响因素多后可以采用的方式是决策表。
        两者比较如下: 

 

矩阵/决策表

面向对象方式

优点:

直接了当,信息获取明确;

随相关因素的增长,维护的复杂度曲线平缓升高,低于矩阵,决策表;在与,或,非计算上相对明确;层次化结构有助于学习;

缺点:

随相关因素的增长,维护的复杂度曲线快速升高;但在与,或,非计算上不明确;

相关信息获取不十分明确;

本质:

排列组合的平面化结构。这是其优缺点的根源;

排列组合的层次化结构;

开发:

运行时确定,变更相关因素对于开发有重大影响;

转化为部署时确定,运行时结构明确

        在维护成本考虑,应该考虑多态,系统设计上不一定用面向对象编程实现,但在流程和计算设计上至少要模拟面向对象的方式;
        1.3 行为下的规则
        分解后的行为,除了处理怎么做的流程,还有各种各样的规则:包括了Selection的Specification外,还包括Validation的Specification,Build的Specification以及Calculation的Specification。
        除了后两种是行为外(不包括它们参数的来源),其它两种业务规则本身来说,其有三种实现方式:
        a) 多态(面向对象方式)。
        b) 简单决策表(映射表),用显示的行表(and关系)保存路由选择(运行时确定)。
        c) 树形决策表(映射表),用显示的树表(and/or关系)保存路由选择(运行时确定)。
        1.4. 行为的异步分解
        大部分行为的分解,都是同步的!然而在复杂系统中还是存在行为的异步分解,这样设计看起来更像是Data Flow Pattern,存在的理由不一,有的是出于性能原因,有的出于业务原因(在金融系统中可以看到这样的例子,例如:为了保证关键业务数据的存在,通常是一些价格或者利率,白天提请的交易行为,分为两步,第一步即使完成,而第二步动作必须在晚上进行)。