zoukankan      html  css  js  c++  java
  • 分析模式读书心得之责任模式

    分析模式读书心得之责任模式

    Martin Fowler的《分析模式》买了许久,也看了很多遍,始终未能全部领会。这篇读书心得也只是疏浅的一点看法而已。

    要说责任模式(Accountability)还需要先从组织架构的程序实现谈起。凡是一个项目,或多或少都要涉及到部门组织架构的描述。目前我们的解决方法无非就是两种:一种是需要递归的处理方式,另外是一种不需要递归的处理方式。

    所谓需要递归的处理方式,就是每一个部门采用如下的数据结构存储:depart(dept_id,parent_id, ...)。这样的优点是可以表示无限的级别,缺点是处理速度慢,大部分都要用到递归。
    所谓不需要递归的处理方式,就是每一个部门采用如下的数据结构存储:depart(levelcode, ...)。这里的levelcode是一种具有层次关系的数据结构,比如字符串方式:company.software.development.java_team,或者类似邮政编码的方式0105080905。这样的优点是处理速度快,直观,通常不需要递归,缺点是表达受到存储容量的限制(比如字段长度等等)。

    为了表达的需要,我们以下例子都采用需要递归的结构来表达。

    现在就提出问题了,很多时候部门结构并不是单一的,参考常用的矩阵式项目组织结构,一个项目组既需要向公司的项目管理机构负责,也需要向所在的部门负责,这种结构我们如何来表示?

    一般来说,如果世界只是这么简单的话,我们毫无疑问可以把刚才的部门定义修改成这样:project(proj_id, dept_id, proj_mgr_id, ...)。事实上程序分析设计人员要面临的世界很复杂,如果需求中公司的CEO准备直属领导该项目的时候怎么办?所以我们需要寻找一种更有效和更简单的表示方法,来适应这种多个层次结构体系同时并存的情况。

    《分析模式》把部门、项目、公司甚至于个人都笼统地概括为“组织(Organization)”。通过使用一个中间对象(表)替代我们上述的直接id关联,就可以支持多个层次同时并存的情况。它给出的定义是这样的:

    class Organization
    {
     OrganizationStruct[] Parents; 
     OrganizationStruct[] Children;
     
    }


    class OrganizationStruct
    {
     Organization Parent;
     Organization Child;
     OrganizationStructType StructType;
     TimeLimit Limit;
    }


    enum OrganizationStructType{Project2Project, Depart2Project, Company2Project, }

    class TimeLimit
    {
     DateTime Begin;
     DateTime End;
     
    bool IsFinished;
    }



    但是这样的结构虽然灵活性够高,但是约束性不够。因为用以上的结构,我们同样可以把“项目”描述为“公司”的上级部门了。那么如何增加这种结构的约束性呢?很简单,把OrganizationStructType从一个简单的enum定义成一个实体就可以了:

    class OrganizationStructTypeEntity
    {
     OrganizationStructType StructType;
     
     
    bool Check(Organization parent, Organization child); // 规则
    }

    然后用OrganizationStructTypeEntity替换OrganizationStruct中的OrganizationStructType就可以了。当添加一个新的关系的时候,我们可以用Check来验证一下,确保数据合乎正常的逻辑。当然,这里给出的代码并不是最优化的,仅仅是为了说明一个概念而已。

    《分析模式》中的“责任类型”并不光是用来解决组织架构组织的问题。现实中普遍存在有各种层次性的关系,包括各种组织架构、合同等等。不过《分析模式》中定义“责任类型”的应用范畴是“可变的”关系,这也是为什么我们需要有一个 TimeLimit 存在的原因。对于描述“爸爸”和“儿子”的数据结构关系的时候,我们就需要用开始的id直接关联的方式;但是如果描述的是“监护人”和“被监护人”的概念,我们就可以应用“责任类型”的模式了。

    当我们把“组织结构”关系抽象升华到“责任类型”的层次的时候,我们需要一组专门的名次来替代以前的提法,所以我们把以上的代码修改一下:

    class Party
    {
     Accountability[] Commissioners;  
    // 委托方
     Accountability[] Responsibles;  // 责任方
     
    }


    class Accountability
    {
     Party Commissioner; 
    // 委托方
     Party Responsible; // 责任方
     AccountabilityType StructType;
     TimeLimit Limit;
    }


    enum AccountabilityType{Project2Project, Depart2Project, Company2Project, Contract, }

    class TimeLimit
    {
     DateTime Begin;
     DateTime End;
     
    bool IsFinished;
    }



    责任类型模式的应用面当然比单纯的“组织结构”要广泛的多。更重要的是,我们程序的复杂度并没有增加。这里摘抄书本中的两个例子:
    John Smith为某公司工作,这里可以被建模为一个责任类型,其中某公司是委托方,John Smith是责任方,责任类型是雇佣关系。
    John Smith允许Mark医生作内窥镜检查,这里可以被建模为一个患者许可类型的责任模型,其中Mark医生对John Smith负责。

    但是,责任依然给模型带来了复杂性,因为责任类型显然要比组织结构类型要多得多。这个将带来我们应用上的麻烦:我们要为新的责任类型编制规则--每个责任类型都要一个规则!如果这个要放到数据库中去,可就麻烦了。

    所以我们还需要改进这个模式,就是要把这些约束相关的数据抽取出来,和具体的算法独立开来。《分析模式》告诫我们一个建模的原则:“把模型清晰地分解成操作级和知识级”。这里的“知识级”很多人也称之为“元模型”,但是Martin说明了他不用“元模型”来称呼“知识级”的原因。

    知识级的代码描述如下:


     

    class AccountabilityType
    {
     PartyType Commissioner; 
    // 委托方
     PartyType Responsible; // 责任方
    }


    class PartyType
    {
     AccountabilityType[] Commissioners;  
    // 委托方
     AccountabilityType[] Responsibles;  // 责任方
    }


    操作级的代码描述如下:

    class Accountability
    {
     AccountabilityType Type;
     Party Commissioner; 
    // 委托方
     Party Responsible; // 责任方
     TimeLimit Limit;
     SomeAction[] Actions;
    }


    class Party
    {
     PartyType Type;
     Accountability[] Commissioners;  
    // 委托方
     Accountability[] Responsibles;  // 责任方
    }



    一旦有了知识级的描述之后,我们很容易用外部的代码来验证其中的约束关系:
     所有的 Party.Comissioners 必须隶属于 PartyType.Comissioners。
     所有的 Party.Responsibles 必须隶属于 PartyType.Responsibles。

    有了“知识级”的概念之后,我们的“责任类型”又可以保存到数据库中去了。当然,做这样的划分目的并不只是为了能够放到数据库中哦。

    我们还继续要对“责任模式”进行改进,因为我们遇到了新问题:小王是一个项目经理,同时因为常见的原因又兼任项目的系统分析员。使用以上的模型,我们可以把小王看作是项目经理,也可以看作是系统分析员,但是不能两者都是。当然我们有很多的折衷办法来处理面前的这种情况,也可以采用《分析模式》给我们的解决方法:让团体类型可以相互继承。这样我们就可以创建一个“项目经理兼分析员”的团体类型了。修改之后的代码如下:

    class PartyType
    {
     PartyType[] BaseTypes;
     AccountabilityType[] Commissioners;  
    // 委托方
     AccountabilityType[] Responsibles;  // 责任方
    }

    回过头来我们再来评估一下:“总公司、区域分公司、分公司、销售办事处”这样的序列是否可以用“责任模式”来描述。因为“责任模式”和直接id关联的方式相比,就是放宽了约束,现在我们通过以上步骤,把约束能力大大加强了,做这个评估,就是要看一下我们的模式是否能够很好地兼容“老方法”,这个也是系统设计过程中常用的一种验证方法。

    我们需要定义“区域分公司责任类型”来对“总公司”负有“区域管理”的责任,定义“分公司责任类型”对“区域分公司”负有“管理分公司”的责任,定义“分公司责任类型2”对“总公司”负有“管理分公司”的责任,定义“销售办事处责任类型”对“分公司”负有“管理销售办事处”的责任,定义“销售办事处责任类型2”...,定义“销售办事处责任类型3”...。不过要这样来定义确实太笨拙了,有没有更好的改进方法呢?

    当然有!我们可以扩展出一种新的“分级的责任类型”,用它定义一个“公司层次结构”的责任类型,然后该责任类型中的每一级都跟一个团体类型的序列“总公司、区域分公司、分公司、销售办事处”中的对应类型相关联。《分析模式》把这种责任类型叫做“分级的责任类型”,与此对应,我们先前讨论的责任类型就叫做“分层的责任类型”。《分析模式》中认为两者的区别在于:“分层的责任类型扑火团体的责任关系并组成一个层次性的模型”,也就是说“团体只能负有一种该类型的责任”;而“分级的责任类型”则是用于捕获其中具有固定次序的团队责任关系”。改良之后的代码如下:


     

    class AbstractAccountabilityType
    {
     PartyType Commissioner; 
    // 委托方
     PartyType Responsible; // 责任方
    }


    class PartyType
    {
     PartyType[] BaseTypes;
     AccountabilityType[] Commissioners;  
    // 委托方
     AccountabilityType[] Responsibles;  // 责任方
    }


    class Accountability
    {
     AccountabilityType Type;
     Party Commissioner; 
    // 委托方
     Party Responsible; // 责任方
     TimeLimit Limit;
     SomeAction[] Actions;
    }


    class Party
    {
     PartyType Type;
     Accountability[] Commissioners;  
    // 委托方
     Accountability[] Responsibles;  // 责任方
    }


    class LevelAccountabilityType // 分层的责任类型
    {
     PartyType Commissioner; 
    // 委托方
     PartyType Responsible; // 责任方
    }


    class HierarchicalAccountabilityType
    {
     
    string Level; // 例如:01020304或aa.bb.cc.dd.ee 表示层次位置,不过这里只需要用1,2,3,4的单数序号了,更简单
     PartyType[] Lists; // 团体类型序列

     PartyType Commissioner; 
    // 委托方
     PartyType Responsible; // 责任方
    }



    这里没有描述书本中图2.13“反复权衡责任类型的子类型”,因为看书看来看去,没有找到什么“定向的责任类型”的说明,而且四处找不到可用的英文版的文档下载,谁可以提供一下,万分感谢。

    最后,在责任模式的操作范围定义中,提出了责任模式可以引入“职位”的概念,所有的职责可以和职位关联,然后个人再和职位做一个“雇佣”的责任模型,不过书中建议除非职位变化很快,否则就不要再引入太多了。

  • 相关阅读:
    COCOS2D-X中UI动画导致闪退与UI动画浅析
    使用cocos2d-x3.4结合cocos2.1.5制作小游戏《亲亲小熊》
    algorithm 学习之 for_each
    cocos2dx 3.2 Touch Listen和menu回调实现截屏
    Lua 中string.gsub(sourceString, pattern, replacementString) 返回值有两个
    python 装饰器模式 我的理解
    Https SSL Knowledge & how to get a self-signed certificate on ubuntu.
    公钥和私钥的理解
    Openwrt UCI 快捷切换SS 配置
    iptables ipset 实用命令
  • 原文地址:https://www.cnblogs.com/BigTall/p/190224.html
Copyright © 2011-2022 走看看