Money
Represents a monetary value.
- 世界のコンピュータの大部分は金絡みの計算をする
- 主だった言語が第一級のMoney型を提供しないのが不思議で仕方がない
-
言語が型を提供してくれないので、通貨がらみの問題がおこる
- 単一通貨ならそれほどでもない
- 複数通貨が絡むと、例えばドルと円を足してしまうのを避けたくなる
-
丸めの問題も
- 100円を3人で分けたら1円どっかに行ったりする
-
これらの問題をMoneyクラスを作って解決せよ
- 主だったライブラリがこういったクラスを提供していないのも不思議で仕方がない
How It Works
- 額面と通貨単位とを持つのが基本の考え
- 額面は整数型もしくは固定小数
-
浮動小数は絶対避けろ
- Moneyが避けようとしている丸めの問題を引き起こす
-
使途は2つありうる
- 通貨の最小単位に量子化(1セントとか)
- 小数単位(0.1セントとか)
- 使途ごとに計算時の振る舞いがまったく異なるので、型を分けるべき
-
MoneyはValue Objectである
- 等価判定、ハッシュ操作は額面と単位の照合で行われる
-
算術操作ももつ
-
加減算
-
単位を考慮に入れる
- 通貨違いはエラーにする
-
Money Bag by Ward Cunningham
- 複数通貨のmoneyを集約
-
- 乗除算
-
-
金の分配となると難題が発生する
- 5セントを70%と30%に分配する
- 3.5セントと1.5セント
- 四捨五入すると 4 + 2 = 6
- 五捨六入すると 3 + 1 = 4
- 5セントに戻らない
-
どうする
-
1円くらいよくない?
- 経理が信じられないくらい神経質になるからダメ
-
最後の取り分を引き算で算出する
- 誤差が蓄積する
-
丸め方針を指定できるようにする
aMoney.multiply(0.3, ROUND_UP)
みたいな感じ- 結局プログラマが気をつけないといけない
- とっ散らかる
-
分配関数を用意する(著者おすすめ)
aMoney.allocate([7,3]): list<Money>
みたいな感じ- 分配関数を使わないといけない」ということをプログラマが覚えていないといけないのが難点
-
-
そもそも、乗除算と分配とは意図が異なる
- 乗除算: 税金計算とか
-
通貨換算
aMoney.convertTo(Currency.DOLLARS)
とかそういうの- 換算のロジックはconverterクラスにカプセル化するのが賢明
-
比較
- ソートできるようになる
-
やはり通貨を考慮
- 通貨違いはエラーor換算
- print,parseのロジックをカプセル化するのもMoneyの役目
-
RDBへの永続化
-
RDBは金の重要性を知らない(RDBMSベンダはそうじゃないのに)
- 【補】それ専用の型がない、の意か
-
Embedded Valueを使うと良い
- 額面カラムと通貨カラム
- 勘定書の中で全部同一通貨なら、レコードごとに通貨をもつのはやりすぎ
-
When to Use It
-
使う理由
- 丸めの振る舞いのカプセル化
- 複数通貨の取り回し
-
反論
-
プリミティブ型に比べてパフォーマンスが悪化する
- 著者は、パフォーマンスに特段の悪影響を及ぼす例を聞いたことはほぼない
-
カプセル化することによってむしろチューニングしやすくなる
-
Example: A Money Class (Java)
- ほぼ略
- doubleとかlongとかdecimalとかをとるコンストラクタを用意する
equals(Object):bool
,equals(Money):bool
生やす- 通貨一致のアサートも生やす
allocate(long[]):Money[]
生やす
英語
-
conundrum
- A confusing and difficult problem or question.