Хорошо, поэтому я хотел узнать мнение по этой теме.
У меня есть тупой объект данных - CustomerOrder.
CustomerOrder имеет цену и количество, но также имеет свойство TotalCash (цена * количество). поэтому у меня есть свойство totalCash, но я не хочу помещать вычисления в объект напрямую, потому что это нарушило бы правило глупых объектов данных. Мне нужно снова и снова получать денежный поток по всему приложению, поэтому мне нужно централизовать расчет. Я мог бы создать класс cashFlowCalculator и передать customerOrder, но мне не нужен другой класс для каждого простого вычисления.
Есть идеи или лучшие практики?
Хороший вопрос - производные / вычисляемые свойства настолько распространены. Я бы хотел увидеть, как из этого появятся некоторые передовые практики.





Я понимаю, почему нужно хранить объекты данных отдельно от бизнес-логики. Используя LINQ с классами, созданными дизайнером, я чувствую себя комфортно, расширяя сгенерированный класс частичной реализацией класса, содержащей бизнес-логику. Я чувствую, что этого разделения достаточно для моих нужд. Если это не сработает для вас, у меня будут и объекты данных, и бизнес-объекты - возможно, с соответствием 1-1, а может и нет. Фабричный класс или метод можно использовать для преобразования между вашим бизнесом и объектами данных. Затем просто реализуйте свою бизнес-логику в своих бизнес-объектах, не прибегая к вспомогательным объектам для ваших вычислений.
В той же ситуации я бы нарушил «правило глупых объектов данных», поскольку не ожидаю, что этот конкретный расчет будет часто меняться. Я бы, наверное, реализовал это как геттер.
Для более сложных сценариев имеет смысл создать класс OrderCalculator, который принимает классы, связанные с порядком, и может выполнять всевозможные вычисления, такие как включенный налог, измерение маржи и т. д. Таким образом вы делегируете ответственность за выполнение вычислений вне CustomerOrder. Таким образом, CustomerOrder не нужно знать о государственном налоге в Техасе, например, чтобы определить, нужен ли налог с продаж.
Почему вы не применяете методы расширения?
public sealed class CustomerOrder
{
public decimal Price;
public decimal Quantity;
}
public static class CustomerOrderExtensions
{
public static decimal GetTotalCash(this CustomerOrder data)
{
return data.Price*data.Quantity;
}
}
вы даже можете переместить статические классы своего расширения в другое пространство имен.
Если это объект передачи данных (DTO), который обновляется из таблицы данных, я бы предложил добавить столбец данных TotalCash в таблицу и установить для свойства столбца данных Выражение значение «цена * количество». Создайте свойство TotalCash только для чтения в нем (DTO) классе, которое будет обновляться из таблицы данных. С точки зрения объектно-ориентированного подхода так и должно быть.
другой вариант [вероятно, здесь слишком простой для опытных ;-)] - позволить тупому объекту данных иметь свойства для вычисляемых полей, но позволить SQL-запросу, который извлекает данные, выполнить вычисление (один раз); конечно сделайте эти поля доступными только для чтения
Я думаю, вам следует подумать, действительно ли вы хотите, чтобы TotalCash было вычисляемым / производным свойством ...
Учтите - если бизнес-логика меняется для расчета, изменение свойства TotalCash задним числом для существующих записей может быть нежелательным.
Я бы подумал о том, чтобы сделать свойство невычисленным членом DTO, и, возможно, также использовал бы сервисный класс TotalCostCalculation, используемый для определения установленного значения.
только мои 2 цента.
Я бы сделал расчет TotalCash в вашем DTO (это будет YAGNI). Если в будущем вам потребуется изменить поведение TotalCash, возможно, стоит подумать о создании TotalCashCalculator и передать его в Ордер через DI.
Вы используете наборы данных и таблицы данных?