为了账号安全,请及时绑定邮箱和手机立即绑定

简化 DDD 实体类状态转换

简化 DDD 实体类状态转换

C#
富国沪深 2022-01-09 16:11:38
我第一次尝试以 DDD 方式开发应用程序。我有一个实体类,它可以有多个状态,并且为了从一种状态转换到另一种状态需要遵循规则。我有一个字典,其中键是实体可以转换到的状态,值是可以转换状态的状态:protected static readonly IDictionary<State, State[]> aGoodName = new Dictionary<State, State[]>{    { State.Approved, new State[] { State.Requested } },    { State.Standardized, new State[] { State.Approved } },    { State.Queued, new State[] { State.Standardized, State.Succeeded, State.Failed } },    { State.Running, new State[] { State.Queued } },    { State.Succeeded, new State[] { State.Running } },    { State.Failed, new State[] { State.Running } },    { State.Completed, new State[] { State.Succeeded } },    { State.Canceled, new State[] { State.Requested, State.Approved, State.Standardized, State.Succeeded, State.Failed, State.Queued } }};我有一个具有所需状态作为参数的通用方法,并检查它是否可以从以下位置转换:public void Transition(State state){    if (!aGoodName[state].Contains(State))    {        throw new ArgumentException($"Cannot change state from {State.ToString()} to {state.ToString()}.");    }    State = state;}但是,如果我理解正确,DDD 方法是用开发人员和业务人员都能在一定程度上理解的语言表达域代码,例如,拥有一种方法会更有意义,比如继承:public void Succeed(){    Transition(State.Succeeded);}甚至:public void Succeed(){    var states = new List<State> { State.Running };    if (!states.Contains(State))    {        throw new ArgumentException($"Cannot change state from {State.ToString()} to {State.Succeeded.ToString()}.");    }    State = State.Succeeded;}我对这种设计模式相当陌生,想知道上面哪种方法最适合 DDD。
查看完整描述

1 回答

?
www说

TA贡献1775条经验 获得超8个赞

我认为您问题的答案首先取决于另一个问题:


这些状态在您的领域中有多重要?

这里重要的是在设计中考虑领域文献(又名无处不在的语言)。但实施细节实际上取决于问题的重要性。他们甚至可以是独立的实体!


entity.To(new ApprovedState());

如果状态转换只是一个标志数据,那么您在此处提供的第一个实现可能就足够了,但如果它更重要并且有更多的业务规则围绕它,您可以使用第二个实现,或者像 State 或 Strategy 这样的模式。


interface IState{...}


class Approved : IState {...}


class Requested : IState {...}


class Entity{

   public IState State {get; set;}

}

最后你可以提供一层薄薄的 fluent API 来更精细地表达你的领域(当然你也可以这样设计......):


TheEntity.IfItsPossible().Approve();

更新

这里还有一件事。有时我们向实体添加字段,就像我们对数据库中的表执行相同操作一样。这就是数据库世界的工作方式!但我认为这在 DDD 中完全不同。也许这些不同的状态实际上扮演着不同实体的角色或隐藏的业务规则,需要深入挖掘。假设Request不是 Reload 实体的状态,而是人们在需要 Reload 时创建的实体。就像您在需要购买产品时创建订单一样。


public class Reload

{

}


public class Request

{

    public string User { get; set; }

    public DateTime Time { get; set; }

    // and other logics about requests

}


public interface IFactory

{

    Reload Create(Request request);

}

如果这真的是域中发生的事情,那么这些状态只不过是其他实体和域服务的内部工作的结果。例如,标准化状态就是我们所说的在队列中等待处理的重新加载,您可以从应用程序的模块中查询这些信息:


public interface IQueueService

{

    void Push(Reload reload);

}



public IEnumerable<Reload> GetStandardizedReloads()

{

    return _queueService.Items();  

}


public IEnumerable<Request> GetRequests()

{

    return _requestRepository.GetAll();

}


查看完整回答
反对 回复 2022-01-09
  • 1 回答
  • 0 关注
  • 294 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信