领域驱动设计 用DDD重构会计凭证生成(下)(11)


新的凭证领域服务之所以能如此简洁 , 主要是源于将全部的凭证创建业务逻辑封装到了以及其调用的和中 。这里就需要先聊几句DDD中的角色定位了 。DDD中的领域服务不同于我们习以为常的包含所有业务逻辑的传统 , DDD中的领域服务是一个组织者兼协调员 , 它负责将一个业务操作所需的各种元素汇聚到一起 , 并指挥这些元素执行相应任务来完成业务操作 , 但其本身并不包含任何业务逻辑 。
的核心方法如下 。
class VoucherCreator {private final BillAggregation billAggregation;private final VoucherKindEnum voucherKindForCreate;private final VoucherRepository voucherRepository = SpringUtil.getBean(VoucherRepository.class);private VoucherCreator(BillAggregation billAggregation, VoucherKindEnum voucherKindForCreate) {this.billAggregation = billAggregation;this.voucherKindForCreate = voucherKindForCreate;}public CreateResult createVoucher() throws VoucherCreateException {List voucherIds = new LinkedList<>();if (billAggregation.getItems().isEmpty()) {log.warn("单据[billId:{} | billType:{}]没有明细数据", billAggregation.getBill().getID(), billAggregation.getBillType());return voucherIds;}if (CreateVoucherChecker.cannotBeCreatedVoucher(billAggregation)) {log.info("单据[" + billAggregation.getBill().getID() + "]的类型不能生成凭证 。");return voucherIds;}boolean existStandardVoucher = existVoucher();if (existStandardVoucher && VoucherKindEnum.STANDARD == voucherKind) {log.info("单据[" + billAggregation.getBill().getID() + "]的标准凭证已生成 。");return voucherIds;}if (!existStandardVoucher && VoucherKindEnum.REFUND == voucherKind) {log.info("单据[" + billAggregation.getBill().getID() + "]的<标准凭证>还未生成 , 不能生成退票凭证 。");return voucherIds;}VoucherRuleHolder voucherRuleHolder = VoucherRuleHolderFactory.getRuleHolder(billAggregation);for (VoucherAmount voucherAmount : voucherRuleHolder.getVoucherAmounts(billAggregation)) {for (VoucherRule voucherRule : voucherRuleHolder.getRules()) {Voucher voucher = VoucherAssembler.assemble(billAggregation, voucherAmount, voucherRule, voucherKind);voucherRepository.save(voucher);voucherIds.add(voucher.getID());}}return voucherIds;}...}
去掉凭证服务
经过上述重构 , 凭证微服务也就没有了存在的意义 , 因为它的功能已经全部移到门面服务中 。其实凭证微服务本身就比较多余 , 说白了就是为拆而拆 , 而我也很理解拆分出这个服务的前同仁的目的 , 毕竟以后出去面试时可以说:“我拆分过服务 。。。” 。假如这个系统有一位合格的架构师一定不会允许这样的拆分 。
个人认为 , 服务拆分无非两种目的 , 一个是交给不同人或团队维护 , 降低人之间的耦合;另一个是将一个服务的热点功能拆分为独立服务 , 以提升性能和稳定性 。而该凭证服务不仅没有达到上述两个目的 , 反而是背道而驰 。第一 , 对于新增规则这种需求要同时修改门面和凭证两个服务 , 如果这两个服务交由不同团队或人员来维护的话 , 同一个需求就需要他们共同做出修改 , 这样的沟通成本其实是可以省掉的 。第二 , 如果凭证服务使用一个独立的数据库实例 , 那么还可以认为它在系统的稳定性提升方面上发挥了作用 , 但事实上是它与门面服务共用一个数据库实例 , 因此拆分出的凭证服务在性能和稳定性方面不仅没有任何贡献 , 反而徒增了一个故障点 , 如果凭证服务挂掉 , 即使门面服务正常运行也不能生成凭证 。