原创 | 使用 JPA 实现 DDD 持久化 - 领域模型:对象的世界
第三节 领域模型:对象的世界
我们以自营类电子商务领域为例,说明如何通过JPA
实现对象持久化。本项目的代码可以在github
网站https://github.com/dayatang/jpa-sample-tmall下载。
领域模型内容体现在tmall-domain
模块中。
下面是领域模型:
说明:
值对象
Money
、ContactInfo
和Address
:分别作为单属性值对象和多属性值对象的例子。Money
值对象代表金额,实质上是对BigDecimal
的封装。为什么要定义Money
值对象而不是直接使用BigDecimal
?因为Money
的含义比BigDecimal
更加适合业务领域,而且可以定义各种金额特定的格式和方法。ContactInfo
代表联系人信息。Address
代表送货地址。BaseEntity
(为了防止UML
图太复杂,没有出现在图中):所有实体的抽象基类,用于定义所有实体的共同属性。BaseEntity
定义了实体类的两个共同属性:id
和version
。id
属性定义了实体的标识符。所有的实体都需要定义一个标识符属性,用来在同类型实体中区分每一个实体实例。通常映射到数据库表的主键列。version
属性用于为并发处理持久化对象时添加乐观锁。实体类
ProductCategory
和Product
:分别代表商品类别和商品。每个商品归属到一个类别。类别之下可以定义若干个子类别。类别之间通过父子关系形成多层的类别树。没有父类别的产品类别是一级类别,相当于每棵类别树的树根。实体类
Pricing
:商品定价实体。用来记录对某个商品的每次定价。为什么不将商品单价建模为商品的一个简单属性?因为:(1)单价会由于成本变化或促销考虑而经常变动,而商品的其他属性很少发生变化。将不同变化频率的属性划分到不同的对象中是分析设计的最佳实践。(2)如果将商品单价建模为商品的属性,每次调价都会覆盖掉原来的单价,定价历史被抹掉了,既无法无法查询历史价格,也无法对价格和销量的关系进行统计分析。而使用单独的Pricing
实体类会存留每次的调价信息,具有巨大的查询和分析价值。(3)企业中管理商品品类的人和负责定价的人通常分属不同的部门。应该尽量根据用户类别来划分软件结构。实体类
Buyer
:买家实体。有两种类型的买家:个人买家PersonalBuyer
和组织买家OrgBuyer
,前者表示买家是一个自然人而后者表示买家是一家组织机构,两者除了包含一些共同的属性之外还分别包含一些不同的属性。共同属性在父类中定义,不同属性在不同的子类中定义。实体类
Order
和OrderLine
:分别代表订单和订单条目。从领域含义来说,订单条目OrderLine
应该建模成为值对象,因为它的生命周期完全从属于订单实体Order
。但是OrderLine
是统计分析的首要目标对象,由于JPA
的某些限制,只有将它建模为实体才能充分发挥针对订单条目的统计分析功能。因此我们通过级联持久化和孤儿删除等技巧,配合部分编码实现,使得OrderLine
得到类似于值对象的效果。实体类
OrderStatusTransition
:订单状态转移实体。记录订单状态的每一次变迁。不将订单状态作为一个简单属性定义在订单类中的原因是:(1)我希望作为事务性数据的订单是不可变的。(2)存留订单状态变迁的历史有助于未来的查询和分析,例如计算收款与发货之间的平均时间差,以利于改进流程。
详细内容请戳这里↓↓↓
这一节就讲到这里,下一节我们讲"O/R映射元数据:映射注解分组"。
如果觉得有收获,点个【赞】鼓励一下呗!
版权声明: 本文为 InfoQ 作者【编程道与术】的原创文章。
原文链接:【http://xie.infoq.cn/article/d7e929951fa3d6515fc26bf63】。文章转载请联系作者。
评论