Вопрос моделирования данных - разделение данных и логика вычислений и доступа

Хорошо, поэтому я хотел узнать мнение по этой теме.

У меня есть тупой объект данных - CustomerOrder.

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

Есть идеи или лучшие практики?

Вы используете наборы данных и таблицы данных?

Igor Zelaya 15.01.2009 07:31

Хороший вопрос - производные / вычисляемые свойства настолько распространены. Я бы хотел увидеть, как из этого появятся некоторые передовые практики.

chickeninabiscuit 15.01.2009 08:05
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
2
473
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Я понимаю, почему нужно хранить объекты данных отдельно от бизнес-логики. Используя 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.

Другие вопросы по теме