代码之家  ›  专栏  ›  技术社区  ›  Fabio Marreco

在其生存期内更改聚合行为

  •  0
  • Fabio Marreco  · 技术社区  · 6 年前

    假设我们有一个生命周期的集合,这样它就可以在生命周期中改变它的行为。在生命的第一部分,它可以做一些事情;在第二部分,它可以做其他事情。

    我想听听关于我们应该如何限制聚合在每个阶段可以做什么的意见。 为了让它更具体一点,让我们以金融贸易为例。

    • 交易者创建 贸易 通知合同及其价格。
    • 风险经理验证交易,并给出理由。
    • 后台可以将交易提交到分类帐,提供会计信息。
    • 交易提交后,会计信息不可更改。

    贸易显然有三个不同的阶段,我称之为 类型化的 , 已验证 提交

    我的第一个想法是用 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层次结构(在其中我必须隐藏基本方法!)?哎呀!).

    我只是想知道你们在这些情况下做什么,如果有更好的方法的话。

    2 回复  |  直到 6 年前
        1
  •  2
  •   Andre    6 年前

    我喜欢每个州都有不同类型的想法。我认为这是一个干净的设计。从逻辑的角度来看,新创建的交易明显不同于提交的交易。

    public Interface ITrade
    {
        Guid Id { get; }
        Contract Contract { get; }
        decimal Price { get; }
    }
    
    public class Trade : ITrade
    {
        public Trade(Guid id, Contract contract, decimal price)
        {
            Id = id;
            Contract = contract;
            Price = price;
        }
    
        Guid Id { get; }
        Contract Contract { get; }
        decimal Price { get; }
    
        public ValidatedTrade Validate(string reason)
        {
            return new ValidatedTrade(this, reason);
        }
    }
    
    public class ValidatedTrade : ITrade
    {
        private ITrade trade;
        private string validationReason;
    
        public ValidatedTrade(Trade trade, string validationReason)
        {
            this.trade = trade;
            this.validationReason = validationReason;
        }
    
        Guid Id { get { return trade.Id; } }
        Contract Contract { get { return trade.Contract ; } }
        decimal Price { get { return trade.Price ; } }
    
        public string GetValidationReason()
        {
            return validationReason;
        }
    
        public SubmittedTrade SubmitToLedger(AccountingInfo accountingInfo)
        {
            return new SubmittedTrade(this, accountingInfo);
        }
    }
    
    public class SubmittedTrade : ITrade
    {
        private ITrade trade;
        private AccountingInfo accountingInfo;
    
        public SubmittedTrade(ValidatedTrade trade, AccountingInfo accountingInfo)
        {
            this.trade = trade;
            this.accountingInfo = accountingInfo;
        }
    
        Guid Id { get { return trade.Id; } }
        Contract Contract { get { return trade.Contract ; } }
        decimal Price { get { return trade.Price ; } }
    
        public AccountingInfo GetAccountingInfo() { .. }
    }
    
        2
  •  1
  •   guillaume31    6 年前

    每个状态可以有一个类,而不是单个类。请看Greg Young的这篇文章: http://codebetter.com/gregyoung/2010/03/09/state-pattern-misuse/

    状态模式的常见问题是与持久性问题的摩擦,特别是与ORM的摩擦。由您决定是否值得麻烦的是更好的健壮性和类型安全性。