Пытаясь понять доменно-управляемый дизайн, я продолжаю возвращаться к вопросу, на который не могу дать окончательного ответа.
Как определить, какая логика принадлежит сущности Домена, а какая логика принадлежит Службе домена?
Пример:
У нас есть класс Order для интернет-магазина. Этот класс является сущностью и совокупным корнем (он содержит элементы OrderItems).
Public Class Order:IOrder
{
Private List<IOrderItem> OrderItems
Public Order(List<IOrderItem>)
{
OrderItems = List<IOrderItem>
}
Public Decimal CalculateTotalItemWeight()
//This logic seems to belong in the entity.
{
Decimal TotalWeight = 0
foreach(IOrderItem OrderItem in OrderItems)
{
TotalWeight += OrderItem.Weight
}
return TotalWeight
}
}
Я думаю, что большинство людей согласятся, что CalculateTotalItemWeight принадлежит сущности. Однако в какой-то момент мы должны отправить этот заказ клиенту. Для этого нам нужно сделать две вещи:
1) Определите стоимость доставки, необходимую для доставки этого заказа.
2) Распечатайте транспортную этикетку после определения стоимости доставки.
Для обоих этих действий потребуются зависимости, которые находятся за пределами сущности Order, например внешний веб-сервис для извлечения почтовых тарифов. Как мы должны выполнить эти две вещи? Я вижу несколько вариантов:
1) Кодируйте логику непосредственно в объекте домена, например CalculateTotalItemWeight. Затем мы позвоним:
Order.GetPostageRate
Order.PrintLabel
2) Поместите логику в службу, которая принимает IOrder. Затем мы позвоним:
PostageService.GetPostageRate(Order)
PrintService.PrintLabel(Order)
3) Создайте класс для каждого действия, которое работает с Order, и передайте экземпляр этого класса в Order через конструктор Injection (это вариант варианта 1, но допускает повторное использование классов RateRetriever и LabelPrinter):
Public Class Order:IOrder
{
Private List<IOrderItem> OrderItems
Private RateRetriever _Retriever
Private LabelPrinter _Printer
Public Order(List<IOrderItem>, RateRetriever Retriever, LabelPrinter Printer)
{
OrderItems = List<IOrderItem>
_Retriever = Retriever
_Printer = Printer
}
Public Decimal GetPostageRate
{
_Retriever.GetPostageRate(this)
}
Public void PrintLabel
{
_Printer.PrintLabel(this)
}
}
Какой из этих методов вы выберете для этой логики, если таковые имеются? Какова причина вашего выбора? Самое главное, есть ли набор рекомендаций, которые привели вас к вашему выбору?