加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

域驱动设计 – DDD不变式业务规则和验证

发布时间:2020-12-14 00:48:30 所属栏目:百科 来源:网络整理
导读:我正在寻找关于在哪里添加域实体的验证规则的建议,以及实施的最佳实践.我没有搜索,没有找到我正在寻找,或者我错过了. 我想知道建议的方法是验证属性不是null,在一定范围或长度等…我已经看到几种方法使用IsValid()和其他关于在构造函数中执行的讨论,所以实体
我正在寻找关于在哪里添加域实体的验证规则的建议,以及实施的最佳实践.我没有搜索,没有找到我正在寻找,或者我错过了.

我想知道建议的方法是验证属性不是null,在一定范围或长度等…我已经看到几种方法使用IsValid()和其他关于在构造函数中执行的讨论,所以实体永远不会处于无效状态,或者使用预处理和后处理,而其他使用FluentValidation api,不变量如何影响DRY和SRP.

当使用App Service,Bounded Context,Domain Service,Aggregate Root,Entity layering时,有人可以给我一个很好的例子来说明这些类型的检查.这是怎么回事,最好的方法是什么?

谢谢.

建模域实体时,最好考虑现实世界的含义.假设你正在处理一个Employee实体.

员工需要一个名字

我们知道,在现实世界中,员工必须始终拥有一个名字.员工不可能有一个名字.换句话说,人们不能在不指定其名称的情况下“构造”员工.所以,使用参数化的构造函数!我们也知道员工姓名不能改变 – 所以我们通过创建一个私人设置来防止这种情况发生.使用.NET类型系统验证您的员工是一种非常强大的验证形式.

public string Name { get; private set; }

public Employee(string name)
{
    Name = name;
}

有效的名称有一些规则

现在开始变得有趣了名字有一定的规定.我们来看一下简单的路由,并假定一个有效的名字是不为空或空的.在上面的代码示例中,以下业务规则未被验证.在这一点上,我们仍然可以创建无效的员工!我们通过修改我们的设置来防止这种情况发生:

public string Name
{
    get
    {
        return name;
    }
    private set
    {
        if (String.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentOutOfRangeException("value","Employee name cannot be an empty value");
        }

        name = value;
    }
}

个人而言,我喜欢在私有设置器中使用这种逻辑,而不是在构造函数中.设定者不是完全看不见的.实体本身仍然可以改变,我们需要确保有效性.另外,总是抛出异常!

暴露某种形式的IsValid()方法呢?

取上述员工实体. IsValid()方法在哪里和如何工作?

您是否允许创建无效的员工,然后期望开发人员使用IsValid()检查来检查其有效性?这是一个薄弱的设计 – 在你知道之前,无名的员工将会围绕你的系统巡航造成严重破坏.

但也许你想公开名称验证逻辑?

我们不想捕获控制流的异常.例外是灾难性的系统故障.我们也不想在我们的代码库中复制这些验证规则.所以,也许暴露这个验证逻辑不是一个坏主意(但仍然不是最大的!).

你可以做的是提供一个静态的IsValidName(string)方法:

public static bool IsValidName(string name)
{
    return (String.IsNullOrWhiteSpace(value))
}

我们的财产现在有所变化:

public string Name
{
    get
    {
        return name;
    }
    private set
    {
        if (!Employee.IsValidName(value))
        {
            throw new ArgumentOutOfRangeException("value","Employee name cannot be an empty value");
        }

        name = value;
    }
}

但是这个设计有什么腥味

我们现在开始为我们实体的各个属性生成验证方法.如果属性具有附加的各种规则和行为,也许这是一个迹象,我们可以创建一个价值对象!

public PersonName : IEquatable<PersonName>
{
    public string Name
    {
        get
        {
            return name;
        }
        private set
        {
            if (!PersonName.IsValid(value))
            {
                throw new ArgumentOutOfRangeException("value","Person name cannot be an empty value");
            }

            name = value;
        }
    }

    private PersonName(string name)
    {
        Name = name;
    }

    public static PersonName From(string name)
    {
        return new PersonName(name);
    }

    public static bool IsValid(string name)
    {
        return !String.IsNullOrWhiteSpace(value);
    }

    // Don't forget to override .Equals
}

现在我们的员工实体可以被简化(我已经排除了空参考检查):

public Employee
{
    public PersonName Name { get; private set; }

    public Employee(PersonName name)
    {
        Name = name;
    }
}

我们的客户端代码现在可以这样看:

if(PersonName.IsValid(name))
{
    employee = new Employee(PersonName.From(name));
}
else
{
    // Send a validation message to the user or something
}

那么我们在这里做了什么?

我们确保我们的域名模型始终保持一致.非常重要无法创建无效的实体.另外,我们用价值对象来提供进一步的“丰富”. PersonName给客户端代码更多的控制权和更多的权力,并且还简化了Employee.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读