利用服务的DDD实体 [英] DDD Entities making use of Services

查看:64
本文介绍了利用服务的DDD实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序正在尝试至少使用名义上的DDD类型的域模型进行构建,并且正在为某些应用程序而苦苦挣扎。

I have an application that I'm trying to build with at least a nominally DDD-type domain model, and am struggling with a certain piece.

我的实体具有一些业务逻辑,这些业务逻辑使用了我目前在某些域服务中拥有的一些财务计算和费率计算,以及我要放入值对象中的一些常量值。

My entity has some business logic that uses some financial calculations and rate calculations that I currently have inside some domain services, as well as some constant values I'm putting in a value object.

我正在努力让实体使用域服务内部的逻辑,或者这些服务内部的逻辑是否甚至属于该域。这是我到目前为止所拥有的:

I'm struggling with how to have the entity use the logic inside the domain services, or whether the logic inside those services even belongs there. This is what I have so far:

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

}

我觉得有些计算逻辑确实属于那些域服务,但是我并不真正喜欢那样,我必须从存储库中手动注入那些依赖项。是否有替代方法可以对此建模?我不喜欢这样会错吗?

I feel like some of that calculation logic does belong in those domain services, but don't really like that I'll have to manually inject those dependencies from my Repository. Is there an alternate way that this should be modeled? Am I wrong in not liking that?

我已经读过《蓝皮书》,但之前并没有真正用这种风格制作任何东西,我正在寻找指导。

Having read the Blue Book but not really built anything in this style before, I'm looking for guidance.

编辑

感谢所有反馈!根据我听到的声音,听起来我的模型应该看起来更像下面的样子。看起来好些吗?

Thanks all for the feedback! Based on what I'm hearing, it sounds like my model should look more like the following. This look better?

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

}

域模型最终变得相当合理贫乏,但随着我添加功能,它可能会更多。

The domain model ends up being fairly anemic at this point, but as I add features maybe it'll have more to it.

编辑2

好的,我得到了更多反馈,也许我的计算服务更像是策略对象,我的实体可以依靠。这是另一种利用实体中更多逻辑的方法,并利用了这些策略对象。有这个想法吗?直接在实体中实例化那些助手有什么问题吗?我想我不想在测试中模拟它们,但是OTOH我也不能在不测试那些策略对象的情况下测试CalculateFinancialGain方法。

Okay, I got some more feedback that perhaps my 'calculation' services are more like strategy objects that it's okay for my Entity to depend on. Here's another take at it with more of the logic back in the Entity, and making use of those strategy objects. Thoughts on this? Any issues with instantiating those helpers directly in the Entity? I don't think I'll want to mock those out in my tests, but OTOH I can't test the CalculateFinancialGain method without testing those strategy objects, either.

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

}


推荐答案

让服务接受 Ticket 实体作为参数。服务应该是无状态的,并且同一服务应该能够向任何数量的实体提供服务。

Have your service accept the Ticket entity as a parameter. Services should be stateless and the same service should be able to provide its services to any number of entities.

在您的情况下,我会拉 FinancialCalculatorService RateCalculatorService 移出您的实体,并使每个服务上的方法接受 Ticket 实体

In your situation I would pull the FinancialCalculatorService and RateCalculatorService out of your entity and make the methods on each service accept the Ticket entity as a parameter.

花点时间阅读 pg。 Eric Evans的域驱动设计中的105

Take a second and read pg. 105 of Domain-Driven Design by Eric Evans

这篇关于利用服务的DDD实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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