Пытаясь разобраться в предметно-ориентированном дизайне, я возвращаюсь к вопросу, на который, похоже, не могу дать окончательного ответа.
Как вы определяете, какая логика принадлежит объекту домена, а какая логика принадлежит службе домена?
Пример: у нас есть класс 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 через Constructor 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)
}
}
Какой из этих методов вы выберете для этой логики, если таковые имеются? Что послужило причиной вашего выбора? Самое главное, есть ли набор руководящих принципов, которые привели вас к вашему выбору?