第三节 领域模型:对象的世界

我们以自营类电子商务领域为例,说明如何通过JPA实现对象持久化。本项目的代码可以在github网站https://github.com/dayatang/jpa-sample-tmall下载。

领域模型内容体现在tmall-domain模块中。

下面是领域模型:

说明:

  • 值对象MoneyContactInfoAddress:分别作为单属性值对象和多属性值对象的例子。Money值对象代表金额,实质上是对BigDecimal的封装。为什么要定义Money值对象而不是直接使用BigDecimal?因为Money的含义比BigDecimal更加适合业务领域,而且可以定义各种金额特定的格式和方法。ContactInfo代表联系人信息。Address代表送货地址。
  • BaseEntity(为了防止UML图太复杂,没有出现在图中):所有实体的抽象基类,用于定义所有实体的共同属性。BaseEntity定义了实体类的两个共同属性:idversionid属性定义了实体的标识符。所有的实体都需要定义一个标识符属性,用来在同类型实体中区分每一个实体实例。通常映射到数据库表的主键列。version属性用于为并发处理持久化对象时添加乐观锁。
  • 实体类ProductCategoryProduct:分别代表商品类别和商品。每个商品归属到一个类别。类别之下可以定义若干个子类别。类别之间通过父子关系形成多层的类别树。没有父类别的产品类别是一级类别,相当于每棵类别树的树根。
  • 实体类Pricing:商品定价实体。用来记录对某个商品的每次定价。为什么不将商品单价建模为商品的一个简单属性?因为:(1)单价会由于成本变化或促销考虑而经常变动,而商品的其他属性很少发生变化。将不同变化频率的属性划分到不同的对象中是分析设计的最佳实践。(2)如果将商品单价建模为商品的属性,每次调价都会覆盖掉原来的单价,定价历史被抹掉了,既无法无法查询历史价格,也无法对价格和销量的关系进行统计分析。而使用单独的Pricing实体类会存留每次的调价信息,具有巨大的查询和分析价值。(3)企业中管理商品品类的人和负责定价的人通常分属不同的部门。应该尽量根据用户类别来划分软件结构。
  • 实体类Buyer:买家实体。有两种类型的买家:个人买家PersonalBuyer和组织买家OrgBuyer,前者表示买家是一个自然人而后者表示买家是一家组织机构,两者除了包含一些共同的属性之外还分别包含一些不同的属性。共同属性在父类中定义,不同属性在不同的子类中定义。
  • 实体类OrderOrderLine:分别代表订单和订单条目。从领域含义来说,订单条目OrderLine应该建模成为值对象,因为它的生命周期完全从属于订单实体Order。但是OrderLine是统计分析的首要目标对象,由于JPA的某些限制,只有将它建模为实体才能充分发挥针对订单条目的统计分析功能。因此我们通过级联持久化和孤儿删除等技巧,配合部分编码实现,使得OrderLine得到类似于值对象的效果。
  • 实体类OrderStatusTransition:订单状态转移实体。记录订单状态的每一次变迁。不将订单状态作为一个简单属性定义在订单类中的原因是:(1)我希望作为事务性数据的订单是不可变的。(2)存留订单状态变迁的历史有助于未来的查询和分析,例如计算收款与发货之间的平均时间差,以利于改进流程。

results matching ""

    No results matching ""