当前位置: 首页 > 编程学习 > 软件工程 > 领域驱动 > 正文

用DDD设计一个电商网站(十一) 最后的准备

2018-04-22 来源:博客园/Zachary_Fan

一、前言

最近实在太忙,上周停更了一周。按流程一步一步走到现在,到达了整个下单流程的最后一公里——结算页的处理。从整个流程来看,这里需要用户填写的信息是最多的,那么在后端的设计中如何考虑到业务边界的划分,和相互之间的交互复杂度,又是我们需要考虑的地方。总体来说本篇讲述的内容在前几篇都有涉及,所以这次一次性处理的业务比较多,已经比较熟练的看官可以跳过本篇。

二、准备

主流的电商设计中结算页包含以下5个概念:选择收货地址、选择支付方式、选择快递、使用优惠券、使用余额和积分。笔者认为,根据我们在本系列的第一篇博文中的上下文映射图,这背后涉及到了多个上下文的协作:

1.用户上下文:包含选择收货地址

2.支付上下文:包含选择支付方式、使用余额和积分

3.售价上下文:使用优惠券。

其中第“1”点我的理解是在整个大系统中,收货地址并不是仅在购买的时候会用到,而是用户可以直接管理的(一般主流电商都可以在《用户中心》菜单内操作个人的收货地址信息),在购物车中进行管理其实并不是一个必须经过的流程,大部分场景下只是在现有地址中做一个选择,所以收货地址更接近于用户域而不是购买域,在购物车的管理可以理解为一个快捷方式而已。

第“2”点,我的理解是,把支付操作相关的概念放到一起,可以做的很灵活,可以和运营打法搭配起来。如:支付方式和使用积分的联动、像天猫那样的红包等促进用户购买欲望的招式。

第“3”点,我的理解是,优惠券也是会影响到整个商品的售价的,所以它应该属于售价上下文,配合其它的促销方式做出更多的打法。

剩下的快递我认为是本地购买上下文内的概念,因为它只服务于购买的流程之中。

三、实现

根据服务能力来编写ApplicationService,那么这里总共是提供了3种服务能力,所以定义了3个ApplicationService来提供这些功能:

1.IDeliveryService:其中包含选择收货地址和选择快递

2.IPaymentService:其中包含选择支付方式、使用余额和积分

3.ICouponService:包含选择礼券。

好了接下来就是其中涉及到的领域模型的设计,这里需要纠正一个之前的错误,在之前的设计中把余额直接放到了User这个值对象中,并且是从用户上下文获取的,现在看看当初的设计不是很妥当。因为余额并不是用户与生俱来的东西,就好比我要认识一个人,并不一定要知道他有多少钱,但是必然需要知道姓名、年龄等。所以余额与用户之间并不是一个强依赖关系。而且分属于2个不同的领域聚合、甚至是上下文。这里涉及的所有领域模型的UML图如下图1所示:

【图1】

其中的值对象都是从远程上下文获取的,所以这里在购买上下文里只是使用了其的一个副本。在购买上下文的3个ApplicationService如下:

    public interface IDeliveryService
    {
        List<ShippingAddressDTO> GetAllShippingAddresses(string userId);
 
        Result AddNewShippingAddress(string userId, DeliveryAddNewShippingAddressRequest request);
 
        Result EditShippingAddress(string userId, DeliveryEditShippingAddressRequest request);
 
        Result DeleteShippingAddress(string id);
 
        List<ExpressDTO> GetAllCanUseExpresses();
    }
    public interface IPaymentService
    {
        List<PaymentMethodDTO> GetAllCanUsePaymentMethods();
 
        WalletDTO GetUserWallet(string userId);
    }
    public interface ICouponService
    {
        List<CouponDTO> GetAllCoupons(string userId);
    }