域驱动设计 - 实体的访问修饰符和执行验证

时间:2013-12-19 21:53:33

标签: validation domain-driven-design

我是DDD的新手,并在stackoverflow和web上阅读有关验证(在哪里放置)的各种讨论。我喜欢将验证保留在实体之外并根据上下文验证它们的想法。在我们的项目中,我们有一个名为MedicalRecord的实体,有一个可以创建或可以保存的实体的规则。我想创建一个服务层,比如RecordService,它会做一些检查以确保用户是否可以在创建医疗记录之前创建医疗记录。我还想创建可以保存医疗记录的MedicalRecordRepository。令我困惑的是访问修改了我的实体和存储库类。由于两者都是公开的,我如何强制我的应用程序的客户端使用该服务而不是仅创建新的医疗记录(使用公共构造函数)并使用存储库来保存它?我正在使用c#。我知道DDD与语言无关,但想知道是否有人可以对此提出一些想法。

感谢。

2 个答案:

答案 0 :(得分:2)

您必须通过使c'tor非公开并允许仅通过工厂创建来控制记录创建:

public class MedicalRecord
{
    internal MedicalRecord()
    {
    }
}

public static class MedicalRecordFactory
{
    public static MedicalRecord Create(User onBehalfOf)
    {
        // do logic here
        return new MedicalRecord();
    }
}

要使internal关键字适用,要么两个类必须位于同一个程序集中,要么类程序集必须允许使用InternalsVisibleTo属性进行工厂程序集访问。

修改

如果您需要能够随时执行验证,则还必须将验证逻辑封装在另一个类中(此处部分通过扩展方法完成):

public static class MedicalRecordValidator
{
    public static bool IsValid(this MedicalRecord medicalRecord, <context>)
    {
        return IsValid(<context>);
    }

    public static bool IsValidForCreation(User onBehalfOf)
    {
        return IsValid(null, onBehalfOf);
    }

    private static bool IsValid(<context> context, User user = null)
    {
        // do validation logic here
    }
}

然后,工厂可以这样做:

public static MedicalRecord Create(User onBehalfOf)
{
    return IsValidForCreation(onBehalfOf) ? new MedicalRecord() : null;
}

你也可以这样做:

if (myMedicalRecord.IsValid(<context>))
{
    // ....

答案 1 :(得分:0)

仅使用您的存储库来检索您的实体;不要保存它们。保存(持久)您的实体是您工作单位的责任。

您让服务更改一个或多个实体(例如MedicalRecord)并跟踪工作单元中的更改。在提交工作单元中的更改之前,您可以验证所有实体以确保跨实体的验证需求。然后你提交你的工作单元(在单个事务中),这将保留你所有的更改,或者根本不存在。

为清楚起见,您的MedicalRecord应该保护自己的不变量;这样客户端使用存储库检索MedicalRecord,调用某些方法来修改它,然后使用工作单元将其保留,应该会产生“有效”的系统状态。如果在某些情况下不是这种情况,则可以认为不应该单独检索MedicalRecord - 它是一些更大概念的一部分。

出于创建目的,使用像@Thomas这样的工厂建议下面是一个很好的方法,虽然我认为我称之为服务(因为实体之间的协作)而不是工厂。我喜欢托马斯的方法是,它不允许客户在没有MedicalRecord(或其他上下文信息)的情况下创建User,而不会将MedicalRecord紧紧地绑在用户身上。