开发者社区 > 博文 > 领域驱动设计和多态实现结合
分享
  • 打开微信扫码分享

  • 点击前往QQ分享

  • 点击前往微博分享

  • 点击复制链接

领域驱动设计和多态实现结合

  • 京东零售技术
  • 2022-01-19
  • IP归属:北京
  • 25480浏览
    序言




    本文是根据本人在工作中的对现有业务的领域驱动重构得出的心得,还有在领域驱动模型上进行需求迭代的经验讲解。

    领域驱动设计(Domain-Driven Design,简称DDD)


    领域驱动设计是使用领域模型表达丰富的软件功能需求.由此实现的软件可以满足用户真正的需要,因此被公认为是软件设计的关键所在。


    多态实现在这特指在同一个领域模型上,通过针对领域模型提供的方法。


    在工作中我是针对现有的电商的商品展示页进行领域模型构建,并在此之上满足复杂多变的需求。



    领域的架构设计




    01
    领域模型的设计



    DDD设计理念,意图在于将业务模块划分成多个独立处理的域,让每个域专注于处理自身的事务,让每个域保持一定的独立性,利于业务进行拆分和组合,通过组合不同域来完成不同的业务功能。


    商品展示页是电商中购买转化率关键的一个页面,用于展示售卖商品的详细信息。


    领域驱动1.jpg


    从业务上对商详进行领域的拆解,可大致拆解为商品基础域,商品完整信息域,促销域,库存域,用户域,门店域等系列业务域。


    领域驱动2.jpg


    域的拆分依据有三个:

    • 业务含义(业务意义)

    • 组织架构层次和结构

    • 降低技术实现复杂度


    业务含义区分是划分域的基本原则,通过区分不同业务的业务含义,将业务的处理进行隔离。在商详中体现于促销域和价格域的区分,对于价格是指商品原本的价格,是和商品进行强关联的,设置出的价格。促销域指的是为了更好地帮助商品售卖设置的一系列销售规则,例如单品降价,多件满减,购买赠品等促销手段。


    组织架构决定系统架构,组织架构区分体现于店铺和门店上,在公司里店铺和店铺评分是在两个部门中维护的,接口的设计和逻辑都独立发展,所以这两个域进行了划分。


    降低单一域的实现复杂度体现在商品基础域和商品完整域中,商品作为商品展示页的重要模型,有着庞大的模型结构和与其他子域的关联逻辑,所以在实现时十分困难。通过将商品拆分成商品基础域(仅包含商品的基本信息)和商品完整域(商品的完整模型结构)来降低技术复杂度。在商品基础域中处理和其他域的关联关系, 在商品完整域中维护商品自身信息。


    02
    域之间的关联关系的设计



    域与域之间难免有关联的逻辑,例如促销需要依赖商品的Id,所属的类目以及一些特殊的业务标识,库存依赖于所在的地址地点,以及商品的相关属性。


    领域模型的设计的初衷就是希望各个域之间能够保持一定的独立性,这种关联关系对于域来说容易破坏域本身的模型独立性,让域之间产生强耦合问题。


    避免破坏域的独立性,我们设计了一个独立于业务的关系网,可以存放域之间实体的关系,保证域的独立性。


    首先我们需要给每个聚合根一个独立且唯一的标识UUID,来标识唯一的实体。


    然后我们在关系网中保存两两UUID之间的关联关系,代表两个聚合根存在着关联关系,但关系网本身对域的业务不关心。


    领域驱动3.jpg


    这样每个域不需要去管理和其他域的关系,做到了独立性,又能在关系网中取得自身所需的关联信息.对于关系网是每个域共享可见的,每个域可以管理自身和其他域之间的关系。


    03
    领域逻辑的多态处理



    领域模型和关系网建立完成后,便需要在此之上处理复杂的逻辑点。


    首先域本身会暴露数个所需要处理的基础业务接口,然后根据不同的业务来编写不同的业务逻辑。我们对接口执行逻辑的分流采用了业务场景进行区分,每个接口在执行逻辑时会对当前的业务场景进行识别,在每个域中对每个业务场景的逻辑处理进行分流,类似于抽象工厂中有不同产品族的划分.这样的划分让不同业务类型的代码做到了归类处理,将功能点进行了解耦,做到了功能的可插拔迭代。


    领域驱动4.jpg



    具体案例




    1. 线上商品转线下售卖——接口维度变动


    背景:

    公司推行线上线下一体化,提了一系列的线下门店售卖需求。这系列需求主要特点是线上售卖的sku需要根据门店进行定制化配置,同一sku在不同门店需要有不同的价格,促销,库存,优惠券。但在一些公共业务维度上,需要保持一致,例如商品标题,主图,规格参数,详细介绍等。


    痛点:

    原商详业务为是以商品为核心做的一个展示业务,线下门店需求需要增加一个门店维度的业务逻辑处理,相应关联的域处理也需要增加门店维度的处理。这改造在以往的传统架构中接口设计,存储,逻辑处理都需要进行大量改造.但通过DDD的设计,拆分数据和结构的做法,这种需求的改造成本有不小的降低。


    解决方案:

    根据门店域是否有实例,判断这个商品是否在门店进行售卖。在门店强相关域中(促销,价格,库存,优惠券)通过场景进行逻辑分流;在公共的通用域里(商品,主图,视频,图文详情)则保持不变。


    领域驱动5.jpg


    通用域不根据oto场景做逻辑判断,逻辑维持不变就行。


    领域驱动6.jpg



    领域模型和多态化处理的优势

    DDD领域开发模型的优势在于:售卖线上商品的系统中增加了一套线下售卖的逻辑处理,同时不影响现有的线上商品售卖业务。并且可以对两种业务场景做场景区分,类似于策略模式,将逻辑进行了分流,使得业务可以变得更灵活,可以灵活去除线下商品业务模式。并且完成这个业务后,整体的业务模型并未受到太大的变动,仅是在关系网中新增了关系和针对线下商品新增实现而已。


    领域模型的多态化的好处:

    • 开闭原则,对已有的逻辑不进行修改,但开放新增新的业务场景,两者还可共同工作。

    • 业务能力的原子化,将线下商品售卖场景当成了一个功能模块加入了进来,对于已有业务是增强的作用。即使以后线下业务被废弃了或者需要修改,改造成本也不会太大。

    • 业务模型的横向扩展性良好,可以将原本单一的商品为核心的业务模型改造成商品+门店为核心的模型,并且未对已有的模型造成太大冲击。


    2. 单商品展示页改造成多商品展示——接口的批量改造


    背景:

    商品展示页中往往要增加同类型商品的展示,例如推荐其他商品,所以原本的单一展示商品页需要展示多个商品,并且不同类型的商品展示的信息不同,相关的逻辑处理也不同。还有种情况是同一个商品在不同店铺中售卖,会有同一商品在不同店铺间推荐,即同一个商品的处理逻辑也不同。


    批量改造的困难点:

    在商详页里,只有一个主skuId(商品编码),就是当前查看商品的skuId,整个商详页的信息除了用户,地址等唯一独立的信息,其余信息都和主skuId强相关。做接口的批量改造模型会受到冲击,没有办法辨识其他域的实例和商品实例间的关联关系。较为简单的办法是在每个域里保存一个skuId做冗余,但这样就破坏了域模型的独立性。


    解决方案:

    在入参上,对于不同类型的商品,在商品基础域中进行标识,做逻辑处理时根据不同商品类型进行分流。

    针对同一个商品在不同门店进行售卖,可以将同一个商品在商品基础域进行冗余,但在具体的逻辑处理上会排重只进行一次处理.

    具体的落地方案还以门店类型商品在批量处理中的分流作为案例.

    一次请求的入参中包含了skuId为555和888的商品,888商品区分为两个门店下售卖,555区分为门店和线上售卖.在和门店强相关的逻辑促销域上的处理如下图:


    领域驱动7.jpg


    在和门店非强相关的商品完整域的处理上如下图:


    领域驱动8.jpg


    每个域根据自身的特点,对不同的业务类型来做区分,促销域对于不同的门店进行了场景的区分,查询不同门店和线上的促销。商品完整域中根据商品skuId来做排重区分,对相同的商品只做一次处理。


    关系网解耦和领域模型多态的优势点:

    关系网提供了业务纵向扩展和横向扩展的可能性,在业务处理逻辑变得复杂时,可以在不太影响领域模型的情况下完成扩展。


    各个域的逻辑分流独立,分流模式多样化。在不同的业务场景下,不同的业务域的业务逻辑处理互不影响,在此之上功能点也可很好的拆分出来,模块化。



    总结




    DDD的模型设计结合多态实现的逻辑分流实现的框架的优点有:

    1. 模型稳定,域属性稳定,并不会因为增加业务模块来源而对自身模型大动变更。整体接口的兼容性和扩展性良好。


    2. 整体功能模块化,可随意组装,对不同的业务需求,可用现有能力进行组装。例如下面的场景:

    a) 普通线上商品,只需要线上商品+促销+库存+门店初始化即可,查询的是线上商品的一套数据。

    b) 全门店商品,线上商品+门店促销+门店库存的初始化+门店和商品和门店的关联关系。

    c) 线上门店商品同时销售,线上商品+促销+库存+门店的初始化+门店促销+门店库存的后处理扩展点+门店和商品和门店的关联关系。


    3. 遵循开闭原则,对已有能力的大幅修改封闭,对新增能力进行替换开放。

    领域驱动设计在面对业务需求的变动时兼容能力十分出色,能保证自身的模型的稳定,也能扩展出不同的业务能力.然后在多态实现的基础上,将功能进行了模块化,让各个业务模块的功能点进行了隔离互相迭代,也共用了很多非必要改造模块的开发。


    此篇文章的内容仅为作者本人在工作上的一些经验和处理方案,如有错误望请指正。


    作者:技数中心黄伟鑫