1

我是 DDD 概念的新手,在从持久层重建我的域模型时遇到了一些问题,即如何处理由于业务规则而通常不允许的对象创建。

例如,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);

解决此问题的最佳方法是什么?

4

1 回答 1

1

在您的情况下,您的最后一个想法似乎是正确的方法。我喜欢至少有三个构造函数:一个“新实体”构造函数、一个“复制实体”构造函数和一个“从持久性重构”构造函数。当然,您可以将相同的行列表添加到不同的发票中,但是何时何地会发生这种情况?请记住,领域驱动设计有助于在代码库中构建业务规则,但在某些时候,您必须接受这样一个事实,即“如果开发人员键入这行代码会很糟糕”,无论如何都是有可能的好吧,您将业务规则建模为代码。

编辑:

只是想补充一点,如果您通过服务层公开域模型,那么您的域模型可以在该项目的程序集内部,并且客户端只需要使用外部可见的数据传输对象或原始类型与服务层交互——这样,消费客户端将不会导致无效操作,并且您的业务逻辑仍然根据问题域整齐地组织,

于 2013-07-07T07:07:45.903 回答