【发布时间】:2011-01-23 18:21:46
【问题描述】:
我有一个应用程序,我正在尝试使用至少名义上的 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);
}
}
【问题讨论】:
-
您能否描述一下“Ticket”与域的关系?
-
我认为票是我的总根。它基本上是对应用程序的增强/缺陷请求。该应用程序正在尝试根据预计的成本/收益来计算特定维护票证的“价值”。
-
您使用的是 IoC 模式吗?我建议将这些计算器移到您可以注入的属性中。将使测试负载更容易。
-
是的,我使用的是 IoC 容器。现在我想起来了,我可以很容易地将这些注入我的实体。我也将我的存储库用作工厂,但我认为我现在需要将它们分开。据我了解,如果我使用的 ORM 会更难做(即注入依赖项),但我不在这里,所以应该很容易。