Здравствуйте, Sinclair, Вы писали:
S>>>Смотрите, в чём затык: для вывода баланса на экран придётся построить новый счёт и попросить данные у него:
S>>>S>>>BalanceLabel.Text = (new Account("03")).CalcCurrentBalance().ToString();
S>>>
SV.>>Нет, поскольку где ж вы возьмете идентификатор? Вообще, идентификатор сугубо служебен и снаружи вам не виден.
S>Как это "не виден"? Да он в плане счетов написан крупным шрифтом. То, что вы дали счёту какой-то внутренний служебный идентификатор — ваше личное решение; нужды в нём никакой нет.
После таких слов Лука Пачоли в гробу перевернулся.
Ваш план счетов — это один-единственный аспект, отчетный. А вы на основе его идентификаторов делаете уникальные ключи, хотя это всего лишь внешние атрибуты (и то, не факт, что прямые, очень может быть, что вычисляемые).
Во-первых, план счетов —
хронотопический стандарт, он действует на территории отдельного государства, и его средняя продолжительность жизни — пять лет. По уму, место его — в справочнике. Чтобы любое количество реальных счетов можно было отнести на счет из текущего плана, а исчезновение из плана идентификаторов не приводило к необходимости переоткрывать счета. Если подумать, из счета даже ссылаться на справочник текущего плана напрямую нельзя. Нужно делать промежуточную таблицу с историей ссылок.
Во-вторых, план счетов —
внешний по отношению к организации стандарт. Есть ведь и другие аспекты помимо налогово-отчетных. В реальной организации на один внешний счет, включенный в отчет, может приходиться 10 внутренних, которые вообще в вышеупомянутом аспекте не видны.
Тут ниже кто-то остроумно написал, что банковский счет это одно, а бухгалтерский — другое. Когда для банков изобретут одни деньги, а для налоговой — другие, тогда это станет правдой. Но не раньше.
Короче, тут не прокладку менять, то есть ООП обсуждать, тут всю систему менять надо. Бухгалтерия — это план счетов, оказывается. Зашибись.
SV.>>Да, хотел дописать почти теми же словами, но решил, что и так понятно. Это некий шорткат, который можно реализовать по-разному (хоть бы и дефолтным значением параметра).
S>Это — плохой способ. Вы прячете ту функциональность, которая должна быть на виду.
"Это" — это что? Сделать шорткат от Current'а на Date.Now?
SV.>>Зрение бывает у дизайнера, а не у дизайна. Как и точка, откуда дизайнер зрит. Это так, к слову.
S>Ну давайте не будем
А почему не будем? Очень даже будем. Дизайн — он безответный, и, прикрываясь его интересами (которых у него нет), можно что угодно запроектировать. Вы ровно это и делаете. Берете произвольное решение, которое нравится вам ("надо его выносить наружу"), и пишете "с точки зрения правильного дизайна". Пойди поспорь. Или надо соглашаться, или начнется совершенно идиотский спор "какой дизайн трушнее". Который закончится взаимным посыланием нафиг и тем, что каждый останется при своем мнении.
Я предлагаю совершенно иной подход — обратить свое внимание на людей, которые будут пользоваться плодами вашей архитектуры. Я с этого начал тему (кто забыл может еще раз прочитать заглавное сообщение) и от нее уходить не собираюсь. Надо каждый раз представлять себе Васю, вчерашнего студента, который пришел на ваш проект, имея представление о счете, как о чем-то с номером, на котором деньги лежат. Зато он знает jQuery и бог в веб-интерфейсах.
Например, Васе поставили задачу — "построение таблицы [счет]-[текущий баланс]". Если вы опять напишете про своих теток, которые паразитируют на реальном труде, приводя сведения о реальном бизнесе в соотетствие с порождением советского Госплана (а откуда же еще высрались эти планы счетов?), которым такая таблица не нужна, не надо, пожалуйста. Мир не крутится вокруг СССР. У других, знаете, тоже бывает бухгалтерия, в которой баланс счета — сумма проводок, а не состояние.
Так вот, выше я предложил сделать шорткат на основе дефолтного параметра. Что вы изволили назвать плохим решением. Видимо, с точки зрения "Правильного Дизайна", который вы тут представляете на манер Лебедева. С точки зрения не Дизайна, а Васи, у него есть объект acc, у которого можно нажать точку и посмотреть, что будет. Вывалится список методов, среди которых не будет никакого CurrentBalance. А будет CalcBalance(Date forDate = Date.Now). Вася, НЕ ЧИТАЯ ДОКУМЕНТАЦИИ, НЕ ИЗУЧАЯ БУХГАЛТЕРИЮ, приобретет новое знание — что баланс счета есть функция от даты и текущий баланс лишь частный случай. При этом Вася останется в блаженном неведении о проводках. Пока что. Пока он находится в рамках
своей задачи.
Теперь заменим Васю на Sinclair'а. Он, конечно, сразу решит, что CalcBalance сводит дебит с кредитом по записям в БД о проводках. И ошибется. Поскольку фабрика на запрос с идентификатором из плана счетов вернет ему сложную реализацию, делегирующую собственно суммирование по проводкам более простым реализациям, сидящим на базе. А сама она будет отбирать реальные счета, отнесенные на интересующий его счет из плана. И суммировать их. А он об этом даже не узнает. Не узнает о том, что система различает реальные счета, и счета из плана. Пока что. Пока он находится в рамках
своей задачи. Такой вот фокус-покус.
Дальше начинается самое интересное. По мере того, как они будут получать новые задачи и решать их, они будут углубляться в объектную модель. Sinclair увидит, что не все счета базируются на проводках. Вася увидит, что CalcBalance() возвращает не Decimal, а Money. У которого есть члены Amount и Currency. И Вася сразу поймет, что он не в шарашкиной палатке работает, а в международной палатке, и счета тут мультивалютные. Следовательно, решит он, должен быть и способ задать интересующую его валюту. Валюту-то он задаст, а получать баланс все равно будет в рублях. И вот Вася задается осмысленным вопросом (НЕ ЧИТАЯ ДОКУМЕНТАЦИИ! НЕ ИЗУЧАЯ БУХГАЛТЕРИЮ В КОНКРЕТНО ВЗЯТОМ ПРЕДПРИЯТИИ!!): почему я передаю в CalcBalance Currency.USD, а мне все приходят наши, деревянные? А если архитектор еще подумает, "No connection to Forex" — ответит Васе на его вопрос исключение.
Резюмируя, ООП решает такие задачи, которые Sinclair перед собой даже не ставит. И автор вопроса о наследовании интерфейсов, мой воображаемый друг, тоже не ставит. Им не нужен Вася, который через полчаса начнет писать код, как будто он всю жизнь работал на проекте. Первый заставит Васю разбираться во всех тонкостях плана (сам не понимая, что план — аспект, как он это показал выше). Второй нахерачит констрейнтов, чтобы Васе жизнь медом не казалась. Разумеется, нахрена им после этого ООП. И так же все работает.
SV.>>С какой точки зрите вы, я не знаю. Мой поинт в том, чтобы сложность разложить по полочкам. Поставьте себя на место гуёвого программиста, которому дела нет до идентификаторов и базы. Зато у него на входе есть счет, который сводит дебит с кредитом по запросу. И полученный таким образом результат можно запихать в форму и отдать операционисту.
S>Я не понимаю вашу терминологию. Вы придумали какое-то решение и хотите общаться только в рамках него?
S>Ну, а я вижу это совершенно по-другому. Конечно же у гуёвого программиста на входе есть исключительно идентификатор. Потому, что ему приехал запрос .../ShowAccountTransactionHistory.aspx?Acc=78.01
S>И теперь ему из этого номера счёта нужно получить всю нужную по ТЗ информацию. Либо ему надо заниматься порождением нафиг ненужной объектной модели, либо можно скормить этот параметр в метод хелперного объекта AccountingService и получить всё, что нужно.
Гуёвый программист не занимается порождением объектной модели. Он отдает 78.01 в метод хелперного объекта AccountingService, и получает объект Account, который можно изучать через IDE. Оба они, AccountingService и Account, а также все реализации Account, описанные выше, являются частью объектной модели, создавать которую (и упаковывая реализацию в которую) дело архитектора.
SV.>>Это зависит от точки зрения дизайнера на responsibility. Если у вас есть дополнительные требования к работе с БД (допустим, поддержка в качестве БД чего угодно, в том числе NoSQL) — ну, введем посредника, который будет делать выборки и другие реляционные операции по чему ему скажут (а Account ему скажет — по проводкам). Если нет — ради бога, прячьте сиквел в реализацию, получите быстрособранную систему, которая жестко завяжется на структуру таблиц. И то, и другое будет понятной объектной моделью, но с разными достоинствами и недостатками в других областях.
S>Это будет нарушением SRP.
Вы не читаете, что ли? Я же сказал:
это зависит от точки зрения дизайнера на responsibility. Если думать о responsibility в терминах "функциональность по расчёту баланса", "функциональность по работе с базой" — тогда да, это нарушение SRP. Если считать responsibility этого класса "предоставить Васе доступ к балансам", тогда нет. Вот когда Account начнет
заодно курсы валют возвращать, тогда это будет нарушение SRP.
Еще раз. Вы просто не ставите такой задачи, которую решает ООП, допустим, в том же самом MS ShP.