我是DDD概念的新手,在从persistance层重建我的域模型时遇到了一些问题,即如何处理由于业务规则通常不允许的对象创建。
例如,Invoice和InvoiceRows的概念。发票已发送给客户后,商务规则不允许将发票添加到发票中。
我的域名模型如下所示:
class Invoice
{
List<InvoiceRow> _rows = new List<InvoiceRow>();
public bool IsSent { get; private set; }
Invoice(bool isSent)
{
this.IsSent = isSent;
}
public InvoiceRow AddRow(Product product, decimal amount)
{
if (IsSent) throw new InvalidOperationException("Invoice already sent to customer.");
var row = new InvoiceRow(this, product, amount);
_rows.Add(row);
return row;
}
public void Send(object service)
{
if (IsSent) throw new InvoiceAlreadySentException();
service.SendInvoice(this);
this.IsSent = true;
}
}
class InvoiceRow
{
public Product Product { get; private set; }
public decimal Amount { get; private set; }
public Invoice Invoice { get; private set; }
InvoiceRow(Invoice parent, Product product, decimal amount)
{
this.Invoice = parent;
this.Product = product;
this.Amount = amount;
}
}
重建发票模型(包括已发送的数据库中的行)时,如果已发送发票,则会出现域模型拒绝添加发票行的问题。
例如:
Invoice invoice = new Invoice(invoiceDto.IsSent);
foreach(row in invoiceRowsDto)
{
invoice.AddRow(row.Product, row.Amount); // Not allowed because the invocie has been sent...
}
当然可以添加带有行列表的构造函数参数,但这样就可以将相同的行列表添加到不同的发票中。
var listOfRows = somelistofinvoicerowsretrievedfromdatabase;
var invoice1 = new Invoice(issent=true, listofrows);
var invoice2 = new Invoice(issent=false, listofrows);
解决此问题的最佳方法是什么?
答案 0 :(得分:1)
在你的情况下,似乎你的最后一个想法是正确的方法。我喜欢至少有三个构造函数:一个“新实体”构造函数,一个“复制实体”构造函数和一个“重构来自持久性”构造函数。当然,你可以将相同的行列表添加到不同的发票中,但是何时何地会发生?请记住,域驱动设计有助于在代码库中构建业务规则,但在某些时候,您必须接受这样一个事实:“如果开发人员键入这行代码那么糟糕”,无论如何都是可能的。好吧,你将业务规则建模为代码。
编辑:
只是想添加,如果您通过服务层公开您的域模型,您的域模型可能是该项目程序集的内部模型,客户端只需要使用任一服务层与服务层接口外部可见数据传输对象或原始类型 - 这样,使用客户端将无法导致无效操作,并且您的业务逻辑仍然根据问题域整齐地组织,