领域驱动设计(DDD)实践之路(一) (4)

领域驱动设计(DDD)实践之路(一)

我直接使用了《实现领域驱动设计》的相关章节的配图,权当是我对这个图的注释吧。

遗留的电子商务系统是个典型的“大线团”,我们按照经验将其在逻辑上拆解为:产品目录子域、订单子域、fa票子域,当然你也可以拆解出更多的子域,甚至将产品目录子域继续向下分解为类目子域、商品子域(虚线是逻辑子域)。另外还有一个专门用于库存管理的库存系统、以及用于销售预测的预测系统。

由于历史原因电商系统里面也存在物流相关的业务逻辑,同时物流又不可避免的作用于库存逻辑之上。而往往最难以把握的就是这部分相交的地方,这才是实际的项目场景,我们通常做法是将其归并为一个新的履约系统,作为一个支撑子域去辅助主要的电商系统。

当然,随着业务不断发展,我们的履约模式(比如支持同城当日达、商家仓储发货、电商集货仓发货、退货等等)、库存类型(调拨库存、越库操作、临期库存、残次库存等等)越来越复杂,我们考虑将其再向下分解为履约系统2.0、库存系统2.0。

核心就是我们可以在概念上使用多个子域来分解较大的界限上下文,也可以将多个分散的界限上下文包含在同一个新的子域当中,最终做到“子域和界限上下文一一对应”。我个人觉得,这个过程是最考验内功心法的地方。

领域驱动设计(DDD)实践之路(一)

上面我们已经说了会拆解出来新的子域,目的使“整洁干净”的界限上下文能够一对一的解决这个子域对应的问题空间,但是随着拆解就必然导致“关联关系”。因为要解决问题空间,必须使用对应的子域,你可以把它拆解出去,但是它始终存在于依赖网中。

我们通用的做法是在相交的地方,定义接口。由支撑的界限上下文去实现,可以做到支撑上下文的插拔式切换。这里仍然是我们强调的“依赖抽象”“解耦”。

2、Repository

“对于每种需要进行全局访问的对象,我们都应该创建另一个对象来作为这些对象的提供方,就像是在内存中访问这些对象的集合一样。为这些对象创建一个全局接口以供客户端访问。为这些对象创建添加和删除方法……

此外,我们还应该提供能够按照某种指定条件来查询这些对象的方法……只为聚合创建资源库”引用自《领域驱动设计》。大家和我的疑问一样,Repository是什么?DAO与Repository什么区别?为什么需要Repository?

首先,Repository 是一个独立的层,介于领域层与数据映射层(数据访问层)之间。

它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接口提供给领域层进行领域对象的访问。Repository 是仓库管理员,领域层需要什么东西只需告诉仓库管理员,由仓库管理员把东西拿给它,并不需要知道东西实际放在哪。其核心还是“解耦”,所以我们应该明确领域层只应该使用Repository获取对象。

接下来,看看DAO与Repository什么区别。

我的理解是这样,你可以将Repository当作 DAO 来看待,但是请注意一点,在设计Repository时,我们应该采用面向集合的方式,而不是面向数据访问的方式。这有助于你将自己的领域当作模型来看待,而不是 CRUD 操作;Repository是面向领域的,Repository定义的目的不是DB驱动的,Repository管理的数据的最小粒度是聚合根,这两点和DAO有很大不同。

通常我们建议把Repository定义为一个集合并且只提供类似集合的接口,比如Add,Remove,Get这种操作。一言以蔽之,我们要用集合的思想来操作聚合根,而不是传统的面向DB的CRUD方法。

后来看看为什么需要Repository,我理解还是“解耦”。当我们把Repository想象成一个资源库,也不关心背后的持久化,这些也不是DDD该思考的东西,我们可以用mysql来实现,也可以用mongo,甚至redis。尤其是当我们在更换底层存储时候,领域层以及相关的服务并无任何影响。

以下是代码示例:

package zwb.ddd.repository.sample.domain; import zwb.ddd.repository.sample.domain.model.BaseAggregateRoot; import java.util.List; /** * BaseAggregateRoot领域模型的基类,BaseSpecification适用于较为复杂的查询场景。 * @author wenbo.zhang * @date 2019-11-20 */ public interface IRepository<T extends BaseAggregateRoot, Q extends BaseSpecification> { T ofId(String id); void add(T t); void remove(String id); List<T> querySpecification(Q q); }

领域驱动设计(DDD)实践之路(一)

领域驱动设计(DDD)实践之路(一)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjfwd.html