1.4 元数据模型实例类

Dna对象描述数据结构的信息(元数据定义部分),元数据的实例部分描述具体领域模型,元数据实例类名为Inst(Instance的缩写),是一个灵活的数据结构,能够表达各种领域模型的对象。Inst类的代码如下所示:

img

关于Inst类的说明:

1)属性 businessType、dnaCode、dnaName表示实例关联到的Dna对象。Inst的属性businessType和dnaCode可以唯一地定位到Dna对象。为了方便使用,dnaName从Dna对象中复制过来,冗余地保留在Inst对象上。另外,Inst中的属性Dna dna既是一个Dna对象引用,也是一个冗余对象。在后台服务中在处理Inst对象时,需要频繁访问businessType和dnaCode对应的Dna对象。为了提升性能,Inst的属性dna冗余记录了Dna对象,通过它则无须根据businessType和dnaCode重复查找Dna对象。

2)属性instType表示Inst的类型,未来有可能根据instType的不同,衍生出不同Inst子类,适用于不同使用场景。

3)当Inst作为条件分页查询返回对象时,total属性被用来记录符合条件的总条数。在非分页条件查询返回Inst对象时,total被设置为-1,表示该属性值没有意义。

4)属性Cell parentCell指向父亲Cell对象的引用,将在下面具体介绍。Cell类里嵌套了Inst类,使得Inst和Cell共同组成了一个树形结构。

5)List〈Cell〉 cells表示该实例对象下的实例值列表。需要注意的是:Inst是实例类,将多个Cell对象通过List组织一起,当Dna对象的maxCount大于1(即实例对象个数超过1)时,需要使用List来记录Cell对象。为了简化,无论是maxCount是否大于1,都使用List〈Cell〉 cells存放实例值。

6)元数据的实例部分由两部分组成:Inst和Cell。Inst称为实例,Cell称为实例值,Inst由实例值Cell对象列表组成。Cell对象才是真正存放具体领域信息的对象。例如,若partyDna下的partyAccountDna的maxCoun大于1,则表示Dna对象partyAccountDna的一个实例对象有多个账户,通过List〈Cell〉 cells来存放多个账户对象,用Inst包装该实例值(Cell对象)列表,以描述实例对象的整体信息。

7)引入Inst类组织Cell的目的是希望除了记录Cell对象List,允许增加额外的描述属性,例如,为了在分页查询返回每一个分页的同时返回总条数,只需要在Inst中增加一个total属性即可。如果不引入Inst类,那么total总条数属性就没有合适地方可以摆放。引入Inst类就可以将多个Cell对象组织在一起放入List中,Inst类的其他属性则是描述这个List的整体信息。

Cell类的代码如下:

img

关于Cell类的说明如下:

1)Cell中的id是唯一主键,parentId表示上层父亲Cell的id。

2)operationFlag表示操作标记,有新增、修改、删除和不变化四个可选值。

3)dnaCode表示Cell对象所对应Dna对象的代码。注意,在Inst中也保存了dnaCode,List〈Cell〉 cells是Inst下的一个属性,一般来说,cells中每一个Cell对象的属性dnaCode值与其所在Inst对象属性dnaCode值相同。但是在某些场景下有用,例如,当Inst对象作为条件查询返回值时,一次查询返回的一个Inst对象的cells包含多个Cell对象,每一个Cell对象可能属于不同Dna对象(它们的businessType值相同,无须冗余保留businessType值)的实例值,有必要记录Cell对象的dnaCode。假设个人客户和企业客户的结构由两个不同Dna对象描述,但是两者保存在同一张数据库表中,在同一个查询中返回多条记录,部分是个人客户,部分是企业客户,这时候需要为每一个Cell对象记录dnaCode值。

4)Map〈String,Va〉表示实例值中每一个属性的值,这是Map对象,Map的key为Vd对象的vdName,即属性名,通过属性名字可以快速访问到对应属性Va对象。

5)Map〈String,Inst〉 children是记录每一个孩子Dna对象的实例对象,例如,Dna对象partyDna有一个子Dna对象partyAccountDna,Map的key则是Dna对象partyAccountDna的属性dnaName值。在当事人元数据模型这个例子中,一个Dna对象partyDna只有一个孩子,意味着其对应的实例值Cell对象的children最多只有一个Map项目。但是在很多应用场景下,一个Dna对象可能有多个Dna子对象,例如一个保单下面可有多个投保人、多个被保险人和多个责任等多个孩子,其对应实例值Cell对象下的children中就有多个Map项目。

6)Inst和Cell类之间的整体逻辑关系如图1-8所示。Inst类通过属性List〈Cell〉 cells组织Cell对象,Cell类通过属性Map〈String,Inst〉children组织Inst对象,相互交叉引用形成了递归树形结构。

img

图1-8 Inst类和Cell之间的整体逻辑关系

7)Cell上owner属性指向Cell对象所在的Inst对象,而Inst对象通过其上属性parentCell指向当前Inst对象的父亲Cell对象。

Cell类的属性Map〈String,Va〉 vas用于存放Dna对象下的属性List〈Vd〉vds中每一个Vd对象所对应的属性值。Va结构如下:

img

关于Va类的说明如下:

1)类Va的code记录对应Vd的属性vdCode值。Vd的vdCode具有唯一性,代表一个Vd对象。

2)类Va的name记录对应Vd的属性vdName值,表示该Va对象对应的Vd的名字。同一个Dna对象属性vds中的每一个Vd对象的name值具有唯一性。因此,为了使用便利性,在业务逻辑处理过程中通过name值来定位Va对象进行业务操作,而不通过Vd的code来定位Va对象。

3)dataType复制了Vd对象的dataType属性值,作为冗余保存,方便后续处理,避免频繁地从Vd对象上访问dataType属性。

4)Object value用于记录属性值,为通用类型Object对象,具体保存的值类型由dataType决定。例如,如果dataType是整型,那么实际存放对象类型为Integer;若是浮点型,则实际存放对象类型为Double;若为字符串,则实际存放对象类型是String,等等。