Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用服务的DDD实体_C#_Domain Driven Design - Fatal编程技术网

C# 使用服务的DDD实体

C# 使用服务的DDD实体,c#,domain-driven-design,C#,Domain Driven Design,我有一个应用程序,我正在尝试用至少一个名义上的DDD类型的域模型来构建,并且正在与某个特定的部分进行斗争 我的实体有一些业务逻辑,它使用我目前在一些域服务中使用的一些财务计算和利率计算,以及我在值对象中输入的一些常量值 我正在努力让实体使用域服务中的逻辑,或者这些服务中的逻辑是否属于域服务。这就是我到目前为止所做的: public class Ticket { public Ticket(int id, ConstantRates constantRates, FinancialCalc

我有一个应用程序,我正在尝试用至少一个名义上的DDD类型的域模型来构建,并且正在与某个特定的部分进行斗争

我的实体有一些业务逻辑,它使用我目前在一些域服务中使用的一些财务计算和利率计算,以及我在值对象中输入的一些常量值

我正在努力让实体使用域服务中的逻辑,或者这些服务中的逻辑是否属于域服务。这就是我到目前为止所做的:

public class Ticket
{
    public Ticket(int id, ConstantRates constantRates, FinancialCalculationService f, RateCalculationService r)
    {
        Id = id;
        ConstantRates = constantRates;
        FinancialCalculator = f;
        RateCalculator = r;
    }

    private FinancialCalculationService FinancialCalculator { get; set; }

    private RateCalculationService RateCalculator { get; set; }

    private ConstantRates ConstantRates { get; set; }

    public int Id { get; private set; }

    public double ProjectedCosts { get; set; }

    public double ProjectedBenefits { get; set; }

    public double CalculateFinancialGain()
    {
        var discountRate = RateCalculator.CalculateDiscountRate(ConstantRates.Rate1, ConstantRates.Rate2,
                                                                ConstantRates.Rate3);

        return FinancialCalculator.CalculateNetPresentValue(discountRate,
                                                            new[] {ProjectedCosts*-1, ProjectedBenefits});
    }
}


public class ConstantRates
{
    public double Rate1 { get; set; }
    public double Rate2 { get; set; }
    public double Rate3 { get; set; }
}

public class RateCalculationService
{
    public double CalculateDiscountRate(double rate1, double rate2, double rate3 )
    {
        //do some jibba jabba
        return 8.0;
    }
}

public class FinancialCalculationService
{
    public double CalculateNetPresentValue(double rate, params double[] values)
    {
        return Microsoft.VisualBasic.Financial.NPV(rate, ref values);
    }

}
我觉得有些计算逻辑确实属于那些域服务,但我不太喜欢,我必须从我的存储库手动注入这些依赖项。是否有其他方法对此进行建模?我不喜欢那是错的吗

我之前读过蓝皮书,但没有真正建立过这种风格的任何东西,我正在寻找指导

编辑

谢谢大家的反馈!根据我所听到的,听起来我的模型应该更像下面的。这个看起来更好吗

public class Ticket
{
    public Ticket(int id)
    {
        Id = id;
    }

    private ConstantRates ConstantRates { get; set; }

    public int Id { get; private set; }

    public double ProjectedCosts { get; set; }

    public double ProjectedBenefits { get; set; }

    public double FinancialGain { get; set; }
}



public class ConstantRates
{
    public double Rate1 { get; set; }
    public double Rate2 { get; set; }
    public double Rate3 { get; set; }
}

public class FinancialGainCalculationService
{
    public FinancialGainCalculationService(RateCalculationService rateCalculator, 
        FinancialCalculationService financialCalculator,
        ConstantRateFactory rateFactory)
    {
        RateCalculator = rateCalculator;
        FinancialCalculator = financialCalculator;
        RateFactory = rateFactory;
    }

    private RateCalculationService RateCalculator { get; set; }
    private FinancialCalculationService FinancialCalculator { get; set; }
    private ConstantRateFactory RateFactory { get; set; }

    public void CalculateFinancialGainFor(Ticket ticket)
    {
        var constantRates = RateFactory.Create();
        var discountRate = RateCalculator.CalculateDiscountRate(constantRates.Rate1, constantRates.Rate2,
                                                                constantRates.Rate3);

        ticket.FinancialGain = FinancialCalculator.CalculateNetPresentValue(discountRate,
                                                            new[] {ticket.ProjectedCosts*-1, ticket.ProjectedBenefits});
    }
}

public class ConstantRateFactory
{
    public ConstantRates Create()
    {
        return new ConstantRates();
    }
}

public class RateCalculationService
{
    public double CalculateDiscountRate(double rate1, double rate2, double rate3 )
    {
        //do some jibba jabba
        return 8.0;
    }
}

public class FinancialCalculationService
{
    public double CalculateNetPresentValue(double rate, params double[] values)
    {
        return Microsoft.VisualBasic.Financial.NPV(rate, ref values);
    }

}
域模型在这一点上相当贫乏,但随着我添加功能,它可能会有更多的功能

编辑2

好的,我得到了更多的反馈,也许我的“计算”服务更像是我的实体可以依赖的策略对象。这里是另一个关于实体中更多逻辑的观点,并利用这些策略对象。对此有何想法?直接在实体中实例化这些助手有什么问题吗?我不想在我的测试中模仿这些,但是如果不测试这些策略对象,我也无法测试CalculateFinancialGain方法

public class Ticket
{
    public Ticket(int id, ConstantRates constantRates)
    {
        Id = id;
        ConstantRates = constantRates;
    }

    private ConstantRates ConstantRates { get; set; }

    public int Id { get; private set; }

    public double ProjectedCosts { get; set; }

    public double ProjectedBenefits { get; set; }

    public double CalculateFinancialGain()
    {
        var rateCalculator = new RateCalculator();
        var financeCalculator = new FinanceCalculator();
        var discountRate = rateCalculator.CalculateDiscountRate(ConstantRates.Rate1, ConstantRates.Rate2,
                                                                ConstantRates.Rate3);

        return financeCalculator.CalculateNetPresentValue(discountRate,
                                                            ProjectedCosts*-1, 
                                                            ProjectedBenefits); 
    }
}

public class ConstantRates
{
    public double Rate1 { get; set; }
    public double Rate2 { get; set; }
    public double Rate3 { get; set; }
}

public class RateCalculator
{
    public double CalculateDiscountRate(double rate1, double rate2, double rate3 )
    {
        //do some jibba jabba
        return 8.0;
    }
}

public class FinanceCalculator
{
    public double CalculateNetPresentValue(double rate, params double[] values)
    {
        return Microsoft.VisualBasic.Financial.NPV(rate, ref values);
    }

}

我会说服务使用实体,而不是相反


另一件事,在您的域中不确定,但您确定票证是一个实体而不是一个值对象吗?

您实际上已经想到了一个已经有相当多讨论的问题。这两条轨道的两边都有信徒,所以你需要自己决定什么才是最有意义的

就我个人而言,我没有让我的实体使用服务,因为它围绕着“如何将服务干净地导入实体?”的问题创建了大量的工作


在我看来,CalculateFinancialGains()更像是一个服务级别调用。这确实会导致票非常贫血,但我认为它有其他行为?如果没有,那可能是一种气味…

让您的服务接受
票据
实体作为参数。服务应该是无状态的,并且同一个服务应该能够向任意数量的实体提供其服务

在您的情况下,我会将
FinancialCalculator服务
RateCalculator服务
从您的实体中拉出,并使每个服务上的方法接受
票据
实体作为参数


让我们看一看

这个问题实际上是《清洁代码》(第96-97页)一书中讨论的一个例子。根本的问题是是否使用过程方法或面向对象方法。希望我没有在这里重复几个部分,但以下是Bob Martin的指导说明:

过程代码(使用数据结构的代码)可以轻松地添加新函数,而无需更改现有的数据结构。另一方面,OO代码可以轻松地添加新类,而无需更改现有函数

这种赞美也是正确的:

由于所有函数都必须更改,因此过程代码很难添加新的数据结构。OO代码很难添加新函数,因为所有类都必须更改

我的理解是,DDD“值类型”就是Bob Martin所说的数据结构


希望这会有所帮助,而不仅仅是增加噪音:)

鉴于我们所看到的课程,我认为它们不是真正的服务,我会把计算器放在
票证中

无论是
FinancialCalculatorService
还是
RateCalculationService
都不依赖于域实体-它们都基于原始值进行操作。应用程序不必担心如何计算票证带来的财务收益,因此将这些信息封装在票证中是很有价值的

如果他们真的没有依赖于域实体,考虑把它们看作“独立类”而不是“服务”(再一次,在蓝皮书术语中)。这当然适用于

Ticket
依赖于策略对象(
FinancialCalculator
RateCalculator
),这些对象本身不具有外来依赖项,也不修改域实体的状态


编辑2的更新。我认为将计算器分成不同的类的好处之一是,您可以独立于
票证
对它们进行测试。严格地说,票证不负责执行这些计算,它们负责对协作类进行正确的调用。因此,我倾向于让它们像在您最初的示例中一样可注入/模拟。

您能描述一下“Ticket”与域的关系吗?我认为Ticket是我这里的聚合根。它基本上是一个应用程序的增强/缺陷请求。应用程序正试图根据预计成本/收益计算特定维护票证的“价值”。您是否使用IoC模式?我建议将这些计算器移动到可以注入的属性。将使测试负载更容易。是的,我正在使用IoC容器。现在我想起来了,我可以很容易地将这些注入我的实体。我也将我的存储库用作工厂,但我想我现在需要将它们分开。据我所知,如果我使用ORM