【问题标题】:Is this considered as procedural programming (or anemic pattern)?这是否被视为程序编程(或贫血模式)?
【发布时间】:2021-01-23 09:25:27
【问题描述】:

假设有两个类,一个是用户类,其中包含用户信息;另一个是支付交易类。 场景很简单,如果用户年龄>65岁,创建A类支付交易;否则,创建 B 类支付交易。

有几种方法可以做到这一点:

  1. 创建一个既不属于用户也不属于事务的方法,只需调用 CreateTransaction。此方法中说明了逻辑:
    func CreateTransaction(user, transaction) {
        if user.GetAge() > 65:
            transaction.CreateA()
        else:
            transaction.CreateB()
    }
  1. 另一个选项是为用户类创建一个方法:
     class User {
        ...
        func CreateTransaction(transaction) {
            if user.GetAge() > 65:
                transaction.CreateA()
            else:
                transaction.CreateB()
        }
     }

然后有一个 CreateTransactionController 方法,调用函数如下:

func CreateTransactinController(user, transaction) {
    user.CreateTransaction()
}

我的问题是,选项 1 是否被视为过程编程,因为逻辑实际上不属于任何对象? (或贫血模式?) 1 和 2 的区别只是放逻辑的地方不同吗?

谢谢!

【问题讨论】:

    标签: oop domain-driven-design procedural-programming anemic-domain-model


    【解决方案1】:

    由于您将此问题标记为 DDD,我将回答由域驱动的模型将如何实现此问题。

    要回答的问题是Transaction 是否包含在User 对象中。如果它是封闭的,则意味着您总是通过用户的记录来获取交易(并且从不直接访问交易)。如果事务本身具有生命周期、可以直接访问、控制域的其他部分等,则它不能包含在 User 中,并且是完整的聚合。

    transaction 包含在user 中意味着用户拥有与事务相关的操作,因此选项2 是正确的方法。

    如果transaction 是不同的聚合,您可以使用Domain Service(如您的选项1),但这是不正确的,因为您同时处理两个聚合(usertransaction)。最好将此功能包含在 Transaction 聚合中。

    下一个要解决的问题是您将如何决定交易类型。一种方法是:

    1. API 请求会将用户的年龄作为请求的一部分发送
    2. 控制器调用服务并将用户的年龄作为整数传递
    3. 服务调用工厂方法,该方法接受年龄为整数,初始化并返回正确的交易类型。
    4. 请求通过时,用户的年龄可能在后端发生了变化,或者请求可能不正确。您可以通过在稍后创建支付交易后运行的“纠正策略”来处理此问题。如果用户的年龄与选择的交易类型相匹配,那么一切都很好。如果不是,则交易被撤销。

    这通常是您处理依赖于来自多个聚合的属性的更改的方式。您继续更改系统中聚合的状态,但稍后再检查相关的聚合数据,如果不一致,则撤消更改。

    更好的方法是创建一个Specification,其明确任务是根据用户的年龄得出正确的支付类型。该规范包含您的业务逻辑 (> 65),为年龄驱动的需求提供上下文,并充当您控制逻辑的中心位置。

    您可以在此处阅读有关规格的更多信息:https://martinfowler.com/apsupp/spec.pdf

    【讨论】:

      猜你喜欢
      • 2017-10-29
      • 1970-01-01
      • 2011-08-17
      • 1970-01-01
      • 1970-01-01
      • 2018-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多