大部分人的疑惑:虽然写了领域里面的通用设计,例如资产入库、出库、调拨,但是在实际的应用中,我们会发现不可能通过领域方法来实现业务,业务通常有条件控制。
我们在最初的领域设计时,首先要考虑通用性,通用性解决的是一个通用领域的问题。
在领域服务之上还有一层业务层,业务层解决具体的问题。
以滴滴为例,业务就是:
- 如果是企业用户则不可以使用优惠券
- 如果是个人用户查询是否有可用的优惠券
- 如果是专车司机则分成比例为 0.8
- 如果是优享司机则分成比例为 0.7
- 如果 。。。。
痛点:编程都是流程式,产品告诉我什么,我就怎么写。
在生活中,数字晶体管的数字显示是通过单个晶体管的亮灭实现的。
如果按照之前的写法,那么就是:
- 如果显示数字 7,则亮 1 2 3 号晶体管。
- 如果。。。
所谓面向对象,就是不按照产品的逻辑思考,不是去分析如何显示数字,而是思考如何控制晶体管的亮和灭。
所有的灯都会有一个编号:
100000, 010000, 000001 …
最终可以通过控制编码 110001 来控制。
出入库实际上就对应商品的可用和不可用,也就对应着灯的亮灭。
以电商系统为例,会有经销商、门店等。
这时候我们会抽象出一个概念——上下文,上下文包含条件里面的企业、个人、专车等。
会将所有的条件放到上下文中,那么基于什么样的条件做什么样的事情,会有一个上下文来协调。
以请假为例,请假实际上对应这一个业务,请假的上下文包含申请人、理由、天数等。
以报销为例,报销对应一个业务,报销的上下文包含金额、银行卡信息。
对于业务而言,最终要得到一个结果,结果就是一个模型(模型就是领域服务中封装的模型)。
上下文封装 OK 了,就可以进入领域层了。
生活中,人力只看单子,领域服务也是一样,单子各项都有了,再进行处理。
编程时会面向上下文编程,拿到上下文会对上下文进行处理/修改。
条件间存在 AND 或者 OR 的关系。
做什么可以做的细粒度一点,我们可以使用优惠券。
每一个 filter 都可以抽象出一个独立的组件,就是领域服务,例如抵消券的接口。
我们会抽象出三大部分:
- 上下文
- 针对上下文的 filter
- 针对上下文的条件(条件也可以理解为一个接口,结果是 true 和 false,如何拼装条件就是连接
参考 querydsl。
- 一个上下文在经过以上步骤的处理下,最终会形成面向领域服务的 model,model 再配合领域服务实现代码的通用性,上层根据业务随时添加组件。
在代码中:
element matcher,实际上来自于 bytebuddy,面向字节码编程的抽象。
面向字节码实际上就是改写 class 的。
bytebuddy 可以用于条件的拼装,所有的条件可以通过组件的形式写上。
扩展方式如下:
如果代码写了 400-500 行,如果上线出问题,只能回滚。
如果使用 filter,改动逻辑,下掉这个 filter 或者上线这个 filter,也就是做一个灰度。
修改条件时,不更改,只新增。
Filter 没有现成的,实际上是我们封装的业务逻辑点。
实际上就是责任链。










