Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
а почему не 200 $
Не очень понимаю зачем столько кода вокруг копеек — судя по MSDN decimal в dotnet это уже структура содержащая целочисленные значения и кол-во знаков после запятой, то есть ваша же Money только factor выражается не как 100, а как 2.
В ПО, которое разрабатывает наша команда используются денежные значения в рублях и копейках. Мы изначально знали, что использование примитивов для выражения денежных значений — это антипаттерн.
decimal не несёт в себе никакой информации о том, что представлено этим числом.
decimal a = 10; //что это?
Compared to floating-point types, the decimal type has more precision and a smaller range, which makes it appropriate for financial and monetary calculations.
…
If you want a numeric real literal to be treated as decimal, use the suffix m or M, for example:
decimal myMoney = 300.5m;
Without the suffix m, the number is treated as a double and generates a compiler error.
А если все-таки когда-нибудь понадобится конвертировать в другую валюту — будете использовать копейки или рубли?
А конвертировать будете в центы или в доллары?
А для каждой валюты будете писать свой класс, где kopeks в названии функции будет заменять на cents/penny/sen и т.п.?
А еще в мире до сих пор не вымерли валюты-динозавры, где бывают 1/1000 части основной единицы, 1/5, 1/12, 1/20 и даже 1/240, и несколько разных могут совместно сосуществовать в одной валюте.
P.S. Stackoverflow тоже советует использовать decimal для хранения денежных значений (там опять же про sql, но не думаю, что decimal в C# сильно отличается в этом плане).
3. Я попробую выразить мысль и скорее всего не только мою — наличествование класса Money это не плохо, но реализация с «копексами» это плохо, Money должен быть общим случаем — это decimal + currency code.
Нет, поменяют имена двух методов на подходящие для всех валют, например HigherUnit и LowerUnit.
Сравнивать SQL с C# я бы вообще не стал. Разные это вещи.
но зачем использовать long для хранения суммы в копейках внутри класса?
для отображения в интерфейсе суммы в копейках или рублях с копейками используется концепция Value Formatter
Вещи разные, но концепция decimal у них одинаковая, и придумана она специально для денежных целей, чтобы не использовать float, который не гарантирует точности, и не городить велосипеды с int/long.
public decimal AmountInRubles {
get {
if (amountInKopecs < KopecFactor)
return amountInKopecs;
return (decimal)amountInKopecs / KopecFactor;
}
}
1. Money(10), а здесь сколько? В вашем случае с 2мя конструкторами это будет 0.1 рубля как я понимаю
2. А если вам будет нужно общаться с системами которым нужна точность до 3 знака? Конечно конвертацию, только почему городим — если система принимает значение умноженное на 100, так с ней и общайтесь — 10m * 100
Я попробую выразить мысль и скорее всего не только мою — наличествование класса Money это не плохо, но реализация с «копексами» это плохо,
public struct Pressure
{
private float value;
private Pressure(float value) { this.value = value; }
public float Pa() { return value; }
public static Pressure Pa(float value) { return new Pressure(value); }
public float hPa() { return value / 100; }
public static Pressure hPa(float value) { return new Pressure(value * 100); }
public float mmHg() { return value / 133.322368f; }
public static Pressure mmHg(float value) { return new Pressure(value * 133.322368f); }
}
«Инкапсулируем примитивное значение в объект-значение, который содержит соответствующие защитные выражения и т.д., для того, чтобы гарантировать, что возможно создать только корректные экземпляры.»
Обратите внимание, что конструкторы закрыты
Если вы напишите класс ZipCode, то он станет оболочкой над string и что дальше?
Инкапсулируем примитивное значение в объект-значение, который содержит соответствующие защитные выражения и т.д., для того, чтобы гарантировать, что возможно создать только корректные экземпляры.
Фаулер однажды сказал, что люди его ненавидят, но рано или поздно приходят к его же мнению, только через набитие шишек.
Money.FromRubles(10) гораздо лучше чем decimal a = 10m;
Есть структура, которая делает код более читабельным
Ну, так тот разработчик сделал глупости, вероятно
и расширяема, если потребуется введение валют.
Что для Вас будет более читабельно — вот это: «new DateTime(2015, 4, 5)», или вот это: «5.April(2015)»?
И здесь я вижу ровно то же самое. Меж тем,, как надо совершенно ясно понимать, для чего создавались те или иные решения, и всегда думать, прежде чем применять что-то, проходя самостоятельно тот путь, который прошли до Вас, но уже гораздо быстрее, т.к. на пути есть указатели. А если Вы сразу переноситесь в конечную точку рассуждений, Вы с очень большой вероятностью оказываетесь не там.
потому что есть другая система, которая принимает всё в копейках.
Мне жаль, что у меня не получается донести до вас мысль о том, что концепцию нельзя представить примитивом.
Не объектов, как объектов, которые имеют поведение, а объектов, которые являются структурами данных
Может быть я не прав, но я воспринял эту статью. как воспитание ненависти к примитивам ради неких призрачных и неописываемых словами мистических концепций.
Помимо пользы, от паттернов проектирования может быть и вред. Бездумное и неразумное использование любого даже самого полезного инструмента или технологии приведет к «абсурду и коррупции». Сколько раз вы сталкивались с проблемой “overengineering-а”, когда для реализации простой концепции использовался десяток паттернов проектирования? В общем, это очередной пример того, что прагматизм и здравый смысл, как всегда является лучшим выбором, и паттерны проектирования – не исключение.
Money как Value Object