3

我试图找到一个清晰而简单的例子来说明贫血域的真正含义。周围有很多理论,也有很多很好回答的问题。尽管如此,我仍然无法清楚地了解“贫血领域”的含义究竟在多大程度上。因此,我相信看到一个贫血域设计的虚拟实际示例会更简单,而不是问你如何将其演变为域驱动的设计......

所以,假设我们有一个TaskData类型的数据实体:

public class TaskData
{
    public Guid InternalId { get; set; }

    public string Title { get; set; }

    public string Details { get; set; }

    public TaskState ExplicitState { get; set; }

    public IEnumerable<TaskData> InnerTasks { get; set; }

}

并且需要一个名为“ ActualState ”的附加属性,它是一个计算状态:如果 Task 有内部子任务,则值严格取决于子任务,否则,“ ActualState ”等于“ ExplicitState

如果我在一个单独的服务类(我称之为“引擎”)中编写这个逻辑,我们有:

internal class TaskStateCalculator
{
    public TaskState GetState(TaskData taskData)
    {
        if (taskData.InnerTasks.Any())
        {
            if (taskData.InnerTasks.All(x => this.GetState(x) == TaskState.Done))
            {
                return TaskState.Done;
            }
            if (taskData.InnerTasks.Any(x => this.GetState(x) == TaskState.InProgress))
            {
                return TaskState.InProgress;
            }

            return TaskState.Default;
        }

        return taskData.ExplicitState;
    }       
}

一个问题是:

即使TaskStateCalculator服务/引擎是我的域层的一部分,上面的代码是否反映了贫乏的域设计?如果是,为了避免这种情况,我们需要移动TaskData类中的逻辑(并将TaskData重命名为Task)。我对吗?

第二个问题是(实际上是一连串):

如果我们遇到更困难的情况怎么办?假设在Task实体中需要一个名为ComputeSomething的属性,并且该属性的逻辑需要访问整个 Task 的存储库。在这种情况下,Task类将依赖于TaskRepository。这样可以吗?EF 如何构造此类的实例?什么是替代方案?

4

1 回答 1

6

我试图找到一个清晰而简单的例子来说明贫血域的真正含义

事实上,从贫乏的领域模型转变为丰富的领域模型真的很容易。

  1. private如果要更改模型的状态,请将所有属性设置器设置为然后添加方法。
  2. 评估所有违反得墨忒耳法则的行为,并在合适的地方添加方法。

最终你会得到一个正确的模型。

在您的情况下,我会将该逻辑封装在其中,TaskData因为您的 TaskStateCalculator 违反了得墨忒耳法则

public class TaskData
{
    public Guid InternalId { get; private set; }

    public string Title { get; private set; }

    public string Details { get; private set; }

    public TaskState ExplicitState { get; private set; }

    public IEnumerable<TaskData> InnerTasks { get; private set; }

    public TaskState GetState()
    {
        if (!InnerTasks.Any())
            return ExplicitState;

        if (InnerTasks.All(x => this.GetState(x) == TaskState.Done))
        {
            return TaskState.Done;
        }

        if (InnerTasks.Any(x => this.GetState(x) == TaskState.InProgress))
        {
            return TaskState.InProgress;
        }

        return TaskState.Default;
    }       
}

另一件事是我可能根本不会向外界公开 InnerTasks 集合(只是将它作为成员字段)。但是很难说,因为我不知道这个类在其他场景中是如何使用的。

为什么选择私人二传手

每次您必须更改多个属性时,通常最好使用方法来描述行为,因为这样就不可能忘记更改所有必需的属性。与更改一组属性相比,方法还可以更好地描述您正在尝试执行的操作。

即使您只更改单个属性,该属性也可以将类设置为无效状态,因为更改可能与类中的其余信息不兼容。不要忘记封装是 OOP 的核心原则之一

于 2014-06-04T10:26:46.783 回答