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