Здравствуйте, SV., Вы писали:
SV.>Это счет-то не соответствует результату операций по проводкам?
Бухгалтер не мыслит о счёте, как о самостоятельной сущности с жизенным циклом, которой можно посылать сообщения и получать результат.
SV.>У нее есть одно большое преимущество — она интуитивно-понятна. Поэтому так строят реальные системы типа ShP OM. А других преимуществ — да, нет.
Интуитивно понятна она ровно до тех пор, пока не начинаются реальные вопросы типа тех, что я задал.
SV.>Есть и недостаток — ОМ чувствительна к дизайну. Кривые руки ее погубят. Поэтому, ШП ОМ — редкая гадость (когда я последний раз смотрел на их CAML, плакал горючими слезами — пакетные запросы адекватно представлены не были, пришлось плюнуть и переписать все на SQL).
Отож.
S>>Смотрите, в чём затык: для вывода баланса на экран придётся построить новый счёт и попросить данные у него:
S>>S>>BalanceLabel.Text = (new Account("03")).CalcCurrentBalance().ToString();
S>>
SV.>Нет, поскольку где ж вы возьмете идентификатор? Вообще, идентификатор сугубо служебен и снаружи вам не виден.
Как это "не виден"? Да он в плане счетов написан крупным шрифтом. То, что вы дали счёту какой-то внутренний служебный идентификатор — ваше личное решение; нужды в нём никакой нет.
SV.>Искать вы будете по внешним атрибутам счета, может быть, даже, в соответствии с правами доступа. Создаваться экземпляр будет фабрикой, внешний вид которой зависит от архитектуры. Разумеется, этот поисковый объект не будет исключительно фабрикой, и я никогда не соглашусь, что это нарушение SRP.
А придётся.
S>>А что такое "Current"? Наверное, есть операция CalcBalanceForDate(Date targetDate), и есть важный инвариант CalcCurrentBalance() == CalcBalanceForDate(new Date()).
SV.>Да, хотел дописать почти теми же словами, но решил, что и так понятно. Это некий шорткат, который можно реализовать по-разному (хоть бы и дефолтным значением параметра).
Это — плохой способ. Вы прячете ту функциональность, которая должна быть на виду.
SV.>Зрение бывает у дизайнера, а не у дизайна. Как и точка, откуда дизайнер зрит. Это так, к слову.
Ну давайте не будем
SV.>С какой точки зрите вы, я не знаю. Мой поинт в том, чтобы сложность разложить по полочкам. Поставьте себя на место гуёвого программиста, которому дела нет до идентификаторов и базы. Зато у него на входе есть счет, который сводит дебит с кредитом по запросу. И полученный таким образом результат можно запихать в форму и отдать операционисту.
Я не понимаю вашу терминологию. Вы придумали какое-то решение и хотите общаться только в рамках него?
Ну, а я вижу это совершенно по-другому. Конечно же у гуёвого программиста на входе есть исключительно идентификатор. Потому, что ему приехал запрос .../ShowAccountTransactionHistory.aspx?Acc=78.01
И теперь ему из этого номера счёта нужно получить всю нужную по ТЗ информацию. Либо ему надо заниматься порождением нафиг ненужной объектной модели, либо можно скормить этот параметр в метод хелперного объекта AccountingService и получить всё, что нужно.
SV.>Это зависит от точки зрения дизайнера на responsibility. Если у вас есть дополнительные требования к работе с БД (допустим, поддержка в качестве БД чего угодно, в том числе NoSQL) — ну, введем посредника, который будет делать выборки и другие реляционные операции по чему ему скажут (а Account ему скажет — по проводкам). Если нет — ради бога, прячьте сиквел в реализацию, получите быстрособранную систему, которая жестко завяжется на структуру таблиц. И то, и другое будет понятной объектной моделью, но с разными достоинствами и недостатками в других областях.
Это будет нарушением SRP.
S>>Если оставить в нём работу с базой, тогда непонятно, почему в нём — почему нам не иметь класс DbManager с методами GetTransfers(Predicate where), кроме которого, в общем-то, ничего и не нужно?
S>>Если оставить в нём работу с расчётом баланса, а проводки отдавать снаружи, то получается, что мы завели целый отдельный класс для примитивов типа
S>>S>>Decimal static CalcBalanceForDate(Date date, allTransfers)
S>> return (from t in allTransfers where t.Date <= date select t.Amount).Sum();
S>>
S>>Зачем всё это делать, совершенно непонятно.
SV.>Как же это непонятно? Допустим, мы завязались на структуру таблиц. Тогда, во-первых, а где это хранить? В каком месте? "Там, где архитектурно правильно" — это общие слова. Где конкретно? Помните про гуёвого программиста, которому нужно состояние счета, атрибуты, балансы и больше ничего? Его вы озаботите знанием этого запроса, в том или ином виде?
Как где? Внутри
сервиса, который знает, как доставать проводки. Делов-то. У нас будет сервис, умеющий из проводок собирать различные отчёты, и будет сервис, умеющий доставать проводки из базы.
Если меняются правила построения отчётов — меняем ровно в одном месте ровно один сервис, и только его нужно тестировать. Если меняется структура таблиц — обратно меняем ровно один сервис и только его нужно тестировать.
SV.>Заглавное сообщение прочитайте еще раз. Всё, что нужно, прекрасно получается безо всяких объектов. Хоть на ассемблере. А вот если подумать о людях, которым с этим кодом работать...
То получится так называемая Anemic Model, в которой логика написана так, что её легко понять и отладить, без попыток сделать "чёрными ящиками" сущности, лишённые тонкостей внутренней структуры.