当前位置: 首页 > article >正文

DDD系列:一、 Domain Primitive

为什么需要Domain Driven Design

​ 软件开发中,降低系统复杂度 是一个永恒的挑战。如使用一些设计模式或范例,从偏技术的角度来降低软件复杂度,而 DDD 的目标是对业务设计提出一种架构思想,进而降低复杂度。

Domain Primitive(DP,最原始的领域):

​ 在一个特定领域里,拥有精准定义的、可自我验证的、拥有行为的 Value Object。

  • DP是一个传统意义上的Value Object,可能拥有 Immutable 的特性*(内部的属性被构建后,不允许被修改)*
  • DP是一个完整的概念整体,拥有精准定义*(对象中属性设值是经过了校验的,是合法的)*,拥有行为
  • DP可以是业务域的最小组成部分、也可以构建复杂组合*(将业务抽象为不可继续分割的对象)*

使用 DP 需要遵循的三个原则

原则一:Make Implicit Concepts Expecit(将隐性的概念显性化)

接口的清晰度

不好的设计:
  public User register(String name, String phone, String address) 

较好的设计:
  public User register(Name, PhoneNumber, Address)

​ 当接口中同一类型参数较多时,使用时容易出错,且不易被发现。

​ 此时可以考虑将同一类型的参数转换为对应的DP模型,使接口变得更清晰、DP内的数据规范化

原则二:Make Implicit Context Expecit(让隐性的上下文显性化)

public class Money {
    private BigDecimal amount;
    private Currency currency;
    public Money(BigDecimal amount, Currency currency) {
        this.amount = amount;
        this.currency = currency;
    }
}

​ 交易过程中,Money中的currency,便是一个隐性的交易属性,将其放在Money对象中,使其凸显出来。

原则三:Encapsulate Multi-Object Behavior(封装 多对象 行为)

public void pay(Money money, Currency targetCurrency, Long recipientId) {
    ExchangeRate rate = ExchangeService.getRate(money.getCurrency(), targetCurrency);
    Money targetMoney = rate.exchange(money);
    BankService.transfer(targetMoney, recipientId);
}


public class ExchangeRate {
    private BigDecimal rate;
    private Currency from;
    private Currency to;

    public ExchangeRate(BigDecimal rate, Currency from, Currency to) {
        this.rate = rate;
        this.from = from;
        this.to = to;
    }

    public Money exchange(Money fromMoney) {
        notNull(fromMoney);
        isTrue(this.from.equals(fromMoney.getCurrency()));
        BigDecimal targetAmount = fromMoney.getAmount().multiply(rate);
        return new Money(targetAmount, to);
    }
}

​ 在跨境支付中(pay),会涉及到汇率转换,为了避免在业务逻辑中去处理汇率计算,我们用DP(ExchangeRate)包装掉“币种转换计算的”动作。计算时需要交易的双端币种、计算费率等计算属性,我们将其都放在一个DP中,封装多个对象完成计算。

常见的DP的使用场景:

  • 有格式限制的String:比如NamePhoneNumberOrderNumberZipCodeAddress等,将隐性的概念显性化
  • 有限制的Integer:比如OrderId(>0),Percentage(0-100%),Quantity(>=0)等,将隐性的概念显性化
  • 可枚举的int:比如Status,将隐性的概念显性化
  • DoubleBigDecimal:一般用到的DoubleBigDecimal都是有业务含义的,比如TemperatureMoneyAmountExchangeRateRating等,将隐性的概念显性化
  • 复杂的数据结构:比如Map<String, List<Integer>>等,尽量能把Map的所有操作包装掉,仅暴露必要行为,将多对象的行为进行封装

DP与其他POJO的区别

与Value Object的对比:

​ Domain Primitive 是 Value Object 的进阶版,在原始VO的基础上要求每个DP 拥有概念的整体,而不仅仅是值对象。在VO的Immutable基础上增加了Validity和行为。当然同样的要求无副作用(side-effect free)。

与Data Transfer Object 的区别

DTODP
功能数据传输 属于技术细节代表业务域中的概念
数据的关联只是一堆数据放在一起,不一定有关联度数据之间的高相关性
行为无行为丰富的行为和业务逻辑

按DP的思维重构老应用的流程

基于重构的原则(影响的代码范围 和 耗时),我们可以使用如下流程:

第一步:

按业务梳理出DP对象与行为,然后从老代码中抽离方法。

所有抽离出来的方法要做到无状态,因为DP属性中,不能带标识状态的数据,所以一切需要改变状态的代码都不属于DP的范畴。

第二步

替换数据校验和跟DP相关的无状态业务逻辑

为了减小该步骤的工作量,可以不修该接口的签名,只修改接口内部的实现。

第三步:

定义一个新的接口,参数使用定义的DP模型。重新编排接口实现类中的逻辑

第四步:

修改外部调用的方式(入参修改为对应的DP模型)。


http://www.kler.cn/a/15480.html

相关文章:

  • 机器学习(基础2)
  • Gin 框架入门(GO)-1
  • 第 14 章 -Go语言 错误处理
  • 6.584-Lab1:MapReduce
  • LeetCode 445.两数相加 II
  • 李秀贤主演警匪片《蓝色霹雳火》
  • 进程状态以及两种特殊进程
  • Java 网络编程 —— Socket
  • C——Typedef是什么?如何使用?有何便利之处?
  • 下载——安装——使用FinalShell
  • 权威学者、企业CFO荟聚上海国家会计学院,共探「智能会计 价值财务」
  • 30基于非对称纳什谈判的多微网电能共享运行优化策略MATLAB程序
  • 最值得学的编程语言是哪个?
  • 10、Java继承与多态 - 内部内的概念与分类
  • hw xm 的额外symbol汇总
  • 为什么要用虚拟 DOM?
  • Open3D 最小二乘拟合二维直线
  • 智能合约的分层设计浅谈
  • 可视化CNN和特征图
  • Java 中的异常处理机制是什么?如何使用它来处理程序中的异常?(七)
  • 玩转ChatGPT:Auto-GPT项目部署与测评
  • 机器学习实战教程(十):逻辑回归
  • 手把手带你写一份优秀的开发求职简历(四)
  • 亚科转债,鹿山转债上市价格预测
  • Leetcode力扣秋招刷题路-0853
  • 能上网的ChatGPT,会带来什么改变