【发布时间】:2018-05-25 14:14:30
【问题描述】:
假设我们有一个具有生命周期的聚合,这样它就可以在其生命周期内改变其行为。在它生命的第一阶段,它可以做一些事情,在第二阶段,它可以做其他事情。
我想听听关于我们应该如何限制聚合在每个阶段可以执行的操作的意见。 为了使其更具体一些,让我们以金融交易为例。
- 交易者创建交易,通知合同及其价格。
- 风险经理验证交易,并说明理由。
- BackOffice 可以将交易提交到分类帐,提供会计信息。
- 交易提交后,会计信息不可更改。
交易显然有 3 个不同的阶段,我将其称为 Typed、Validated 和 Submitted
我的第一个想法是用InvalidOperationExceptions 污染聚合,我真的不喜欢:
public class Trade
{
private enum State { Typed, Validated, Submited }
private State _state = State.Typed;
public Guid Id { get; }
public Contract Contract { get; }
public decimal Price { get; }
public Trade (Guid id, Contract contract, decimal price) { ... }
private string _validationReason = null;
private AccountingInformation _accInfo = null;
public void Validate(string reason) {
if (_state != State.Typed)
throw new InvalidOperationException (..)
...
_validationReason = reason;
_state = State.Validated;
}
public string GetValidationReason() {
if (_state == State.Typed)
throw new InvalidOperationException (..)
return _validationReason;
}
public void SubmitToLedger(AccountingInformation info) {
if ((_state != State.Validated))
throw new InvalidOperationException (..)
...
}
public AccountingInfo GetAccountingInfo() { .. }
}
我可以执行Maybe pattern 之类的操作,以避免Get... 方法出现异常。但这不适用于行为方法(Validate、SubmitToLedger 等)
奇怪的是,如果我要使用函数式语言(例如 F#),我可能会为每个状态创建不同的类型。
type TypedTrade = { Id : Guid; Contract: Contract; Price : decimal }
type ValidatedTrade = { Id : Guid;
Contract: Contract;
Price : decimal;
ValidationReason : string}
type SubmittedTrade = { Id : Guid;
Contract: Contract;
Price : decimal;
ValidationReason : string;
AccInfo : AccountingInfo }
// TypedTrade -> string -> ValidatedTrade
let validateTrade typedTrade reason =
...
{ Id = typedTrade.Id; Contract = typedTrade.Contract;
Price = typedTrade.Price; Reason = reason }
// ValidatedTrade -> AccountingInfo -> SubmittedTrade
let submitTrade validatedTrade accInfo =
...
{ Id = validatedTrade.Id;
Contract = validatedTrade.Contract;
Price = validatedTrade.Price;
Reason = validatedTrad.Reason;
AccInfo = accInfo }
问题会优雅地消失。但要在 OO 中做到这一点,我必须使我的聚合不可变,并且可能创建某种 o 层次结构(我必须在其中隐藏基本方法!?哎呀!)。
我只是想知道你们在这些情况下的做法,以及是否有更好的方法。
【问题讨论】:
标签: oop design-patterns domain-driven-design