最直观的例子是组织结构,上级组织与下层组织之间的关系,从具体层面讲是一种所属关系,Martin将它抽象为一种责任关系。人和组织之间的所属关系是责任关系;管理者与部署之间的关系是责任关系;部门与部门负责人、经理之间的关系是责任关系。书中Martin将这种关系进一步泛化到更广的范围,个人认为没有多少实用价值,因为具体应用中对业务概念不能太泛化,否则将显得很牵强,即软件结构中的某些部位、接口责任过重。另外注意书中一开始就提到模型中的所有概念都是面向接口,而非面向实现,因此对象类型与派生类型之间并不一定是继承关系、各种派生类型也不必是在同一个数据库表中,仅仅是实现某个接口而已
在抽象层面就有一些抽象概念
Party: 参与者,责任关系中任何一方都属于参与者
Accountability: 责任关系,从数据模型来理解就是两个或多个参与者之间的对应关系,以及相关属性
Commissioner: 委托方,从具体例子来讲就是参与者中的所有者(owner)、管理者等
Responsible: 责任方,从具体例子来讲就是参与者中的下层组织、被管理者等
原书中Martin使用对象模型来表述,尤其是使用了非标准的类UML表示(Odell表示法,即ERStudio采用的方法),所以比较难理解。另外的原因就是抽象层次比较高,具体环境中的设计变数很多,对象模型和数据模型之间可能差距较大,对象间职责作用关系有点繁琐,这也是造成难以理解的原因之一
很多大型数据处理型系统中这方面都设计的非常灵活,看起来也很直观,没有概念的干扰没有对象模型的变幻莫测,因此主要使用数据模型的方式做个笔记
pattern 1:
最普通的设计就是采用简单的Adjacency List Model,例如组织结构的设计
数据模型: 对象模型:
![](https://i-blog.csdnimg.cn/blog_migrate/a523f865c9f1cd0a280596fd9725eedc.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/152d764395e0eba5d38394507e37332f.jpeg)
贫血模型中可以使用int ParentId关联上级组织,向前走一点可以使用Organization1 Parent,还可以使用一个IList<Organization1> Children
对于小型组织、公司,这个设计基本能满足要求。情况稍微复杂一些,例如大型生产制造型企业,有工厂生产组织结构、分销渠道组织结构、集团总部行政管理的组织结构,在矩阵型组织中不同的组织结构之间形成矩阵型交叉,例如产品线、项目等,与功能型组织结构就会交叉,这对组织结构的设计要求会比较高
pattern 2:
基于上面的例子考虑稍复杂一点的情况,例如有两个组织结构需要管理,一个销售组织结构,一个生产组织结构,简单的设计可以这样
数据模型: 对象模型:
![](https://i-blog.csdnimg.cn/blog_migrate/c9fc14002951504c888b03175b318bf5.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/be356e01ab5fed3cfbe3cfb69a5c59bf.jpeg)
这是将两棵树存储在一起,每个组织结构可能只属于销售组织结构、生产组织结构,也可能同时属于这两个组织结构,对每一棵树的维护和使用,基本类似pattern 1
pattern 3:
1. 如果有更多的组织结构,采用pattern 2就很难维护;从图论的观点来看,pattern 1和pattern 2都将树节点(node)和树的边(edge,即父子关联关系)存储在一起了。将这两个数据分开存储,就具备进一步扩展的基础了。即将组织对象(节点)和组织结构树型关系(边)分开存储
2. 考虑下面这种组织结构关系:
![](https://i-blog.csdnimg.cn/blog_migrate/94b5baa756a82dab8fb607c182fb0017.jpeg)
集团总部的下面只能是区域总部,区域总部下面只能是分公司,即用组织(节点)来构造树型结构时,需要遵循一定的规则,因此将组织(节点)类型独立提取出来,并在类型上面建立规则。目的是能够方便的添加新的组织(节点)类型,使用规则配置而不需要修改代码,就能建立新的组织结构
3. 不同组织结构同样使用类型区分(组织类型、组织结构类型是两种概念,前者是节点类型,后者是树型结构的类型),每种类型对应一棵树型结构,添加一种新的组织结构图同样只需要添加新的组织结构类型,并进行配置
数据模型:
![](https://i-blog.csdnimg.cn/blog_migrate/0762feaa2ffeb547e0386a5f16710b2b.jpeg)
Organization3Type: 组织类型,例如区域总部、分公司、销售点
Organization3StructureType: 组织结构类型,例如销售组织、生产组织
Organization3: 具体的组织(节点)对象
Organization3Structure: 树型结构
Organization3StructureRule: 规则表,例如组织(节点)对象组成树型结构的规则
数据示例:
![](https://i-blog.csdnimg.cn/blog_migrate/4f3d2161b331488818cc374725f170de.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/195acd9d6906d7a70fa4ca2c3c98d5ba.jpeg)
说明:
1. 对象模型的设计方案比较灵活,不再列出来,以免该死的UML反而产生误解
2. Organization3StructureRule的职责只在于限制Organization3Structure,它描述、约束了树型结构的大致形状。如果要修改规则表中的规则数据,确保Organization3Structure中已经存在的数据符合新的规则是一件麻烦事情
可以这样理解,业务对象是Organization3和Organization3Structure,其它数据、对象只是一些设计构造,目的是便于业务扩展。Martin将其总结为知识层级(knowlege level)和操作层级(operational level),个人不太认同,因为没有必要制造这些概念
3. 添加新的组织类型、新的组织结构类型,配置组织结构树的构成规则,然后就可以维护多种不同类型的组织结构,单从组织结构维护这个功能来看,这已经是一种可配置的设计方案
这个数据模型设计方案对于特定的业务领域已经具备较高的灵活性,因此对象模型没有必要再过于复杂或高度抽象,代码的复杂性带来的问题很可能得不偿失。对象模型做必要的封装,使这个组织结构设计在使用时比较方便就足够了
参考SAP系统。组织结构只是一种基础数据,他们的复杂性不在于数据本身的维护上,而在于其它业务模块对他们的使用。实现灵活的业务设计,基础数据本身的灵活性只是一个方面,如何让业务系统在使用这些基础数据时的逻辑处理规则也具备可配置性,是比较深层次的话题。同样,如果实现了这个目标,对象模型完全没有必要再做过多抽象,与数据模型一一对应也足够用了,这就是SAP、Oracle等这种大型系统中看不到太多面向对象痕迹的原因
从这个观点来看,Martin尝试使用对象模型来描述这些复杂的业务概念模型就是一种错误的选择,也具有一定的误导作用
4. 这个数据模型只是一个简单的示例,实际中可以灵活的变化。
例如在大型生产企业中,所有的组织(节点)对象用一个表来保存可能不大现实,例如公司、工厂、车间通常是生产组织结构的主要类型,他们可能都具备一些基本属性,但都有各自特殊的属性,很自然就会出现下面这种设计方式
![](https://i-blog.csdnimg.cn/blog_migrate/293def443640086d46b4a03a8cb70966.jpeg)
都具备的属性保存在"组织结构基本数据表"中,各自特殊的属性分别保存在公司、工厂等其它表中,使用一对一的关联关系
同样规则也不局限于示例中的这种形式,不同的规则也可以象上面这样分不同的表保存
同样,不管表结构如何设计,对象结构并不一定是继承等关系,组合、聚合、关联等都可以
如果业务模块对这些基础数据的使用也具备较高的可配置性,一般都会存在很多这样的设计方式
抽象的责任模型
既然作为一种模式当然不能局限于组织结构,所以抽象概念就有了参与者Party、责任关系Accountability、委托方Commissioner、责任方Responsible,例如参与者Party的对象模型可能类似于:
![](https://i-blog.csdnimg.cn/blog_migrate/b6f30bceea51f01ec6234652d6b86870.jpeg)
上面pattern 3组织结构示例中的Parent_Org_Id、Child_Org_Id就分别对应到Commissioner、Responsible等
在具体业务设计中完全没有必要使用过于广泛的接口,在特定的问题域内进行适当抽象即可
上图中Organization、Person与Party之间是一种泛化关系,但不一定是接口的继承,形式上可能类似于pattern 3中的Organization3Type,即通过可配置的类型进行泛化,这就是书中提到的Party Type Generalizations
Operating Scope操作范围、Time Period有效时间
例如在BOM结构中有效时间段是必需的,对于operating scope,书中提到的例子那种情况下也是有必要的