zoukankan      html  css  js  c++  java
  • DDD—实体和值对象

    一、实体
         实体是领域模型中的一个对象,带有业务含义的对象,集多个业务属性,业务行为于一体。领域建模时,我们根据业务场景分析,找到跟业务逻辑相关的实体对象,然后按照实体间的关联将多个对象进行聚合。
         实体最大的特点是拥有唯一标识符,这个标识符贯穿整个软件的生命周期,不随业务流程和状态变更后更改,在领域模型中以领域对象DO的形式存在。
         如下代码示例:人事领域里的人员考勤子域,考勤里面有员工对象,员工需要通过上班打卡,下班打卡完成一个完整的考勤行为,这个员工就是一个实体,因为每个人在公司都有工号,是标识这个人的唯一ID,不管他去上海还是北京出差打卡,他的员工ID都不会变化。
      同时实体还会包含跟考勤相关的上班打卡和下班打卡方法,是一个充血模型。
    /**
     * 人员实体
     * @author test11
     */
    public class Person {
    
        //人员id
        private String id;
    
        //姓名
        private String name;
    
        //地址
        private Address address;
    
        //上班打卡
        private void goWork(){
    
        }
    
        //下班打卡
        private void leaveWork(){
    
        }
    
    }
     
    二、值对象
       如上代码示例中,员工的信息由人员id,姓名,所在的省,市,街道组成,我们可以将省,市,街道抽象出来一个Address,构成一个地址的属性集合,这个集合的名称就是地址值对象。
       所以值对象就是一个属性集合,将不同的关联属性组合成了一个概念整体,具有整体概念和不可修改的特性。
    /**
     * 地址值对象
     */
    public class Address {
    
        //省份
        private String province;
        //城市
        private String city;
        //街道
        private String street;
    }
     
    三、实体和值对象
       实体和值对象都是微服务底层最基础的领域对象,实现领域最基本的业务逻辑。
       实体和值对象都是若干属性的集合,实体一般是带有业务含义的的对象,具有业务属性,业务行为和业务逻辑。
       值对象也是若干属性的集合,但他只有数据初始化操作,不涉及数据修改,基本不包含业务逻辑。
          值对象是属于实体的一部分,如果值对象是单一属性,则直接定义为实体的属性,如果值对象是属性集合,则将他设计为值对象类,值对象没有ID,会被实体整体引用。

      

    四、实体和值对象的数据库形态
      实体:将领域模型映射到数据模型时,一个实体(DO)可能对应0,1,多个数据库持久化对象(PO),大多数情况下DO和PO是一对一的关系,当DO只是暂住内存时,也可以不需要持久化。当用户和角色两个实体合并成权限实体时,一个DO则对应了多个PO。当用户实体和订单实体合并到一张表中时,这两个DO的生成需要一个PO的拆分,这是多对一的关系。
      值对象:值对象的数据库设计大都采用了反范式,实体对象的属性值和值对象的属性值集合以JSON形式保存在同一个数据库表中。
      上面的人员和地址的对应关系,设计数据库表时可以有三种方式:
      (1)把地址值对象的所有属性加到人员实体表中:这种设计方式会破坏地址的业务含义和属性完整
       

      (2)创建人员实体的表,关联地址实体表:增加了不必要的实体和表

        

      (3)实体对象的属性值和值对象的属性值集合以JSON形式保存在同一个数据库表中:数据建模时,可以将值对象的属性集合嵌入到实体表中,保留对象的业务含义,同时减少了表的设计,一般是将值对象序列化成大对象JSON串后,嵌入到实体表中的

         

      基于第三种方式的领域模型落地,现在许多数据库都开始支持基于JSON串的CRUD操作了,当然,类似这样值对象的设计,多了可能会使实体堆积一堆缺乏完整意义的属性。

      但是值对象不可变,在并发环境下获取的永远是相同的对象,不会被修改,所以值对象可以被多个实体并发引用,所以高并发场景下的领域对象一般优先设计为值对象而非实体,可以保证线程安全。

      值对象还有一个重要作用,以数据冗余的方式记录业务发生那一刻的数据,比如用户聚合中包含了用户(聚合根,也是实体)和地址值对象,订单生成那一刻,用户和地址信息以JSON的方式冗余进订单数据中,这样避免了订单聚合每次都通过调用用户的聚合根ID获取最新用户信息和地址,解耦了用户聚合和订单聚合,同时用户实体和地址值对象也以冗余的方式,记录了业务的快照数据,还原业务发生前后的场景。

    五、贫血模型和充血模型
        贫血模型:Spring的bean就是一种贫血模型,领域被用来作为属性存储的载体,而没有实现具体方法,比如教育领域的校长,只会记录他的年龄,职级,工作年限,而不会有他的一些行为的方法实现,单单用来作为属性的存储。
        充血模型:实体不止包含对象的属性,也包含他对应的行为的方法实现,而不止仅仅作为属性存储的载体。
     
      

        参考书籍 ——《基于DDD和微服务的中台架构与实现》欧创新、邓頔
        参考书籍 ——《领域驱动设计》Eric Evans
        参考书籍 ——《架构真经》Martin L. Abbott

      
  • 相关阅读:
    关于Hyper-V备份的四大注意事项
    未找到导入的项目,请确认 <Import> 声明中的路径正确
    IDC门外汉-单线、双线、智能多线、BGP的区别
    国内主流云主机比较
    Error : The specified component was not reported by the VSS writer (Error 517) in Windows Server 2012 Backup
    [MSDN] Windows Server 2012 R2 简/繁/英下载
    深入浅出VC++串口编程之基于Win32 API
    Remon Spekreijse CSerialPort串口类的修正版2014-01-10
    Remon Spekreijse CSerialPort用法
    “CObject::operator =”: 无法访问 private 成员(在“CObject”类中声明)
  • 原文地址:https://www.cnblogs.com/jiyukai/p/14824122.html
Copyright © 2011-2022 走看看