DDD不变式业务规则和验证 [英] DDD Invariants Business Rules and Validation

查看:180
本文介绍了DDD不变式业务规则和验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找有关在何处添加域实体的验证规则以及实施最佳做法的建议.我确实进行了搜索,但没有找到想要的东西,或者错过了.

I am looking for advice on where to add validation rules for domain entities, and best practices for implementation. I did search and did not find what i was looking for, or i missed it.

我想知道验证属性在特定范围或长度内不为null的推荐方法是什么...我已经看到了使用IsValid()的几种方法以及有关强制执行的其他讨论.构造函数,这样该实体就永远不会处于无效状态,或者使用预处理和后处理,而其他使用FluentValidation api则可以看到不变性如何影响DRY和SRP.

I would like to know what the recommended way is for validating that properties are not null, in a certain range, or length, etc... I have seen several ways using an IsValid() and other discussions about enforcing in the constructor so the entity is never in an invalid state, or using preprocessing and postprocessing, and others using FluentValidation api, how invariants impact DRY and SRP.

在使用应用程序服务,绑定上下文,域服务,聚合根,实体分层时,有人可以给我一个很好的示例,说明将这些类型的检查放在何处.哪里去了,最好的方法是什么?

Can someone give me a good example of where to put these sorts of checks, when using a App Service, Bounded Context, Domain Service, Aggregate Root, Entity layering. Where does this go, and what is the best approach?

谢谢.

推荐答案

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

When modeling your domain entity, it is best to consider real-world implications. Let's say you are dealing with a Employee entity.

员工需要姓名

我们知道,在现实世界中,员工必须始终有一个名字.员工没有名字是不可能的.换句话说,如果不指定员工姓名,就无法构建"员工.因此,请使用参数化的构造函数!我们还知道员工的姓名不能更改-因此我们甚至通过创建私有设置器来防止这种情况的发生.使用.NET类型系统来验证您的员工是一种非常有效的验证方式.

We know that in the real-world an employee must always have a name. It is impossible for an employee not to have a name. In other words, one cannot 'construct' an employee without specifying its name. So, use parameterised constructors! We also know that an employees name cannot change - so we prevent this from even happening by creating a private setter. Using the .NET type system to verify your employee is a very strong form of validation.

public string Name { get; private set; }

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

有效名称具有一些规则

现在,它开始变得有趣起来.名称具有某些规则.让我们采取简单化的方法,并假设有效名称是一个不为null或为空的名称.在上面的代码示例中,未验证以下业务规则.至此,我们仍然可以创建无效的员工!让我们通过修改设置器来防止这种情况的发生:

Now it starts to get interesting. A name has certain rules. Let's just take the simplistic route and assume that a valid name is one which is not null or empty. In the code example above, the following business rule is not validated against. At this point, we can still currently create invalid employees! Let's prevent this from EVER occurring by amending our setter:

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;
    }
}

就个人而言,我更喜欢在私有设置方法中使用此逻辑,而不是在构造函数中使用.塞特犬不是完全看不见的.实体本身仍然可以更改它,我们需要确保有效性.另外,总是抛出异常!

Personally I prefer to have this logic in the private setter than in the constructor. The setter is not completely invisible. The entity itself can still change it, and we need to ensure validity. Also, always throw exceptions!

如何公开某种形式的IsValid()方法?

What about exposing some form of IsValid() method?

采用上面的Employee实体. IsValid()方法在哪里以及如何工作?

Take the above Employee entity. Where and how would an IsValid() method work?

您是否允许创建一个无效的Employee,然后期望开发人员通过IsValid()检查来检查其有效性?这是一个较弱的设计-在您不知不觉中,无名员工将在您的系统中四处巡游,从而造成严重破坏.

Would you allow an invalid Employee to be created and then expect the developer to check it's validity with an IsValid() check? This is a weak design - before you know it, nameless Employees are going to be cruising around your system causing havoc.

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

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

We don't want to catch exceptions for control flow. Exceptions are for catastrophic system failure. We also don't want to duplicate these validation rules in our codebase. So, perhaps exposing this validation logic isn't such a bad idea (but still not the greatest!).

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

What you could do is provide a static IsValidName(string) method:

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

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

Our property would now change somewhat:

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;
    }
}

但是这种设计有些可疑...

我们现在开始为实体的各个属性生成验证方法.如果属性具有各种规则和行为,则表明我们可以为其创建值对象!

We now are starting to spawn validation methods for individual properties of our entity. If a property has all kinds of rules and behavior attached to it, perhaps this is a sign that we can create an value object for it!

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
}

现在我们的Employee实体可以简化了(我排除了空引用检查):

Now our Employee entity can be simplified (I have excluded a null reference check):

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

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

我们的客户代码现在看起来像这样:

Our client code can now look something like this:

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

那我们在这里做了什么?

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

We have ensured that our domain model is always consistent. Extremely important. An invalid entity cannot be created. In addition, we have used value objects to provide further 'richness'. PersonName has given the client code more control and more power and has also simplified Employee.

这篇关于DDD不变式业务规则和验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆