假设有两个类,一个是用户类,其中包含用户信息;另一个是用户类。另一类是支付交易类。 场景很简单,如果用户的年龄大于65岁,则创建A型支付交易;否则,请创建B型付款交易。
有几种方法可以做到这一点:
func CreateTransaction(user, transaction) {
if user.GetAge() > 65:
transaction.CreateA()
else:
transaction.CreateB()
}
class User {
...
func CreateTransaction(transaction) {
if user.GetAge() > 65:
transaction.CreateA()
else:
transaction.CreateB()
}
}
然后有一个CreateTransactionController方法,调用该函数的方法如下:
func CreateTransactinController(user, transaction) {
user.CreateTransaction()
}
我的问题是,因为逻辑实际上并不归任何对象所有,所以选项1是否被视为过程编程? (或贫血模式?) 1和2之间的差异是放置逻辑的不同地方吗?
谢谢!
答案 0 :(得分:1)
由于您将此问题标记为DDD,因此我将回答由域驱动的模型将如何实现这一点。
要回答的问题是Transaction
对象中是否包含User
。如果将其括起来,则意味着您始终要遍历用户记录以获取事务(并且永远不要直接访问事务)。如果事务本身具有生命周期,可以直接访问,可以控制域的其他部分,依此类推,则不能将其包含在User
中,并且是完整的聚合。
将transaction
括在user
中意味着用户拥有与交易相关的操作,因此选项2是正确的方法。
如果transaction
是一个不同的聚合,则可以使用Domain Service
(如您的选项1),但这是不正确的,因为您要处理两个聚合(user
和{{1} }) 同时。最好将此功能包含在transaction
聚合中。
下一个要解决的问题是如何决定交易类型。一种方法是:
通常这是您处理依赖于多个聚合中的属性的更改的方式。您可以继续更改系统中聚合的状态,但是在稍后的时间检查相关的聚合数据,如果情况不一致,请撤消更改。
一种更好的方法是创建一个Transaction
,其显式任务是根据用户的年龄得出正确的付款类型。该规范包含您的业务逻辑(> 65),为年龄驱动的需求提供了上下文,并充当了控制逻辑的中心位置。
您可以在此处了解有关规格的更多信息:https://martinfowler.com/apsupp/spec.pdf