C# 在不丢失封装的情况下实例化业务实体

C# 在不丢失封装的情况下实例化业务实体,c#,design-patterns,domain-driven-design,C#,Design Patterns,Domain Driven Design,我在域项目中有一个客户业务实体,我想根据其属性在域服务项目中实例化它。有一些业务逻辑在创建时需要强制执行,例如,Salary依赖于FirstName(仅示例)。我不希望它的setter是公共的,这会丢失封装 如何在不丢失封装的情况下实例化/初始化它。setter的private可以更改,而不是public public class Customer { public int Id { get; private set; } public string

我在
项目中有一个
客户
业务实体,我想根据其属性在
域服务
项目中实例化它。有一些业务逻辑在创建时需要强制执行,例如,
Salary
依赖于
FirstName
(仅示例)。我不希望它的setter是公共的,这会丢失封装

如何在不丢失封装的情况下实例化/初始化它。setter的private可以更改,而不是public

 public class Customer
    {
        public int Id { get; private set; }

        public string Firstname { get; private set; }

        public string Surname { get; private set; }

        public decimal Salary { get; private set; }
        //... other properties
    }

如果您对封装有如此严格的要求。。那么您唯一的实际选择(我现在可以想到)就是使用构造函数:

public Customer(string firstName, string surname, decimal salary, ...)

允许像这样直接操纵域对象不是一种罪恶。如果你那么担心会发生什么。。要么给它们提供支持字段,要么让您的实体公开一个公共接口来对其进行更改(这可能会使用某种
保护
类来确定有效性)。

如果您的要求对封装非常严格。。那么您唯一的实际选择(我现在可以想到)就是使用构造函数:

public Customer(string firstName, string surname, decimal salary, ...)

允许像这样直接操纵域对象不是一种罪恶。如果你那么担心会发生什么。。要么给他们提供支持字段,要么让您的实体公开一个公共接口,以便对其进行更改(这可能会使用某种
保护
类来确定有效性)。

通常,您将创建一个客户实例

答:从存储库检索现有的客户。在这种情况下,考虑到在客户存储到存储库之前已对约束进行了验证,您不需要强制执行约束


B:一个全新的客户。如果存在一些重要的域约束,您可以使用工厂来封装创建。

通常,有两种情况下您将创建一个客户实例

答:从存储库检索现有的客户。在这种情况下,考虑到在客户存储到存储库之前已对约束进行了验证,您不需要强制执行约束


B:一个全新的客户。如果存在一些重要的域约束,您可以使用工厂来封装创建。

如果您的验证可以在
Customer
级别工作,建议添加一个属性,例如
IsValid
,该属性在
Customer
对象上运行业务规则。两种实现可以如下所示:

public bool IsValid
{
    get
    {
        return !string.IsNullOrWhiteSpace(Firstname) && Salary > 0;
    }
}

public Dictionary<string, string> IsValid2
{
    get
    {
        var errors = new Dictionary<string, string>(); //TODO: Instantiate only if errors are found

        if (string.IsNullOrWhiteSpace(Firstname))
        {
            errors.Add("ERR_001", "First name is invalid.");
        }

        if (Salary <= 0)
        {
            errors.Add("ERR_002", "Salary should be a positive number.");
        }

        return errors;
    }
}
public bool有效
{
得到
{
return!string.IsNullOrWhiteSpace(Firstname)&&Salary>0;
}
}
公共词典有效2
{
得到
{
var errors=new Dictionary();//TODO:仅在发现错误时实例化
if(string.IsNullOrWhiteSpace(Firstname))
{
错误。添加(“ERR_001”,“名字无效”);
}

if(Salary如果您的验证可以在
Customer
级别工作,建议添加一个属性,例如
IsValid
,该属性在
Customer
对象上运行业务规则。两个实现可能如下:

public bool IsValid
{
    get
    {
        return !string.IsNullOrWhiteSpace(Firstname) && Salary > 0;
    }
}

public Dictionary<string, string> IsValid2
{
    get
    {
        var errors = new Dictionary<string, string>(); //TODO: Instantiate only if errors are found

        if (string.IsNullOrWhiteSpace(Firstname))
        {
            errors.Add("ERR_001", "First name is invalid.");
        }

        if (Salary <= 0)
        {
            errors.Add("ERR_002", "Salary should be a positive number.");
        }

        return errors;
    }
}
public bool有效
{
得到
{
return!string.IsNullOrWhiteSpace(Firstname)&&Salary>0;
}
}
公共词典有效2
{
得到
{
var errors=new Dictionary();//TODO:仅在发现错误时实例化
if(string.IsNullOrWhiteSpace(Firstname))
{
错误。添加(“ERR_001”,“名字无效”);
}

如果(你可能会发现这篇关于设计实体的博文很有趣:你可能会发现这篇关于设计实体的博文很有趣:ctor是保护不变量的最佳位置。我包装了DateTime。现在,我需要使用DateTimeWrapper在客户实体内验证DateOfBirth,但我不能使用依赖项注入,因为构造tor与上面类似。有什么想法吗?tor是保护不变量的最佳位置。我包装了DateTime。现在,我需要使用DateTimeWrapper在客户实体内验证DateOfBirth,但我不能使用依赖项注入,因为构造函数与上面类似。有什么想法吗?