DDD中众所周知的建议是Aggregate Roots不使用域服务。域服务是协调两个聚合根以实现行为。
当我看到Rinat Abdullin写的标题为Building Blocks Of CQRS的博客时,我真的很惊讶。在“域服务”部分下,您将读到域服务已注入聚合根目录。
聚合根可以接受域服务吗?
答案 0 :(得分:8)
在某种程度上是的。如果AR确实需要服务来执行某些的工作,那么您可以将其作为方法参数注入。如果AR需要为其行为的最服务,那么可能是它的模型不正确。
答案 1 :(得分:8)
请忽视那篇文章。它是很久以前写的,是完全错误的。如果使用 AggregateRoot 和 DomainService 模式实现模块,我建议使用更高的逻辑(例如请求处理程序)来负责:
答案 2 :(得分:4)
我发现following explanation相当不错。它基于Vaughn Vernon的书,并且注入'域模型中的域服务通过实际需要此服务的方法调用。
public class PurchaseOrder
{
public string Id { get; private set; }
public string VendorId { get; private set; }
public string PONumber { get; private set; }
public string Description { get; private set; }
public decimal Total { get; private set; }
public DateTime SubmissionDate { get; private set; }
public ICollection<Invoice> Invoices { get; private set; }
public decimal InvoiceTotal
{
get { return this.Invoices.Select(x => x.Amount).Sum(); }
}
public bool IsFullyInvoiced
{
get { return this.Total <= this.InvoiceTotal; }
}
bool ContainsInvoice(string vendorInvoiceNumber)
{
return this.Invoices.Any(x => x.VendorInvoiceNumber.Equals(
vendorInvoiceNumber, StringComparison.OrdinalIgnoreCase));
}
public Invoice Invoice(IInvoiceNumberGenerator generator,
string vendorInvoiceNumber, DateTime date, decimal amount)
{
// These guards maintain business integrity of the PO.
if (this.IsFullyInvoiced)
throw new Exception("The PO is fully invoiced.");
if (ContainsInvoice(vendorInvoiceNumber))
throw new Exception("Duplicate invoice!");
var invoiceNumber = generator.GenerateInvoiceNumber(
this.VendorId, vendorInvoiceNumber, date);
var invoice = new Invoice(invoiceNumber, vendorInvoiceNumber, date, amount);
this.Invoices.Add(invoice);
DomainEvents.Raise(new PurchaseOrderInvoicedEvent(this.Id, invoice.InvoiceNumber));
return invoice;
}
}
public class PurchaseOrderService
{
public PurchaseOrderService(IPurchaseOrderRepository repository,
IInvoiceNumberGenerator invoiceNumberGenerator)
{
this.repository = repository;
this.invoiceNumberGenerator = invoiceNumberGenerator;
}
readonly IPurchaseOrderRepository repository;
readonly IInvoiceNumberGenerator invoiceNumberGenerator;
public void Invoice(string purchaseOrderId,
string vendorInvoiceNumber, DateTime date, decimal amount)
{
// Transaction management, along with committing the unit of work
// can be moved to ambient infrastructure.
using (var ts = new TransactionScope())
{
var purchaseOrder = this.repository.Get(purchaseOrderId);
if (purchaseOrder == null)
throw new Exception("PO not found!");
purchaseOrder.Invoice(this.invoiceNumberGenerator,
vendorInvoiceNumber, date, amount);
this.repository.Commit();
ts.Complete();
}
}
}
答案 3 :(得分:3)