11-Jul-2013 | Like this? Dislike this? Let me know |
Money It's a gas Grab that cash with both hands and make a stash - from "Money", "Dark Side of the Moon", © 1973 Pink Floyd |
Money It's a class Make it so it's safe inside a hash - Buzz Moschetti, with apologies to Roger Waters and programmers everywhere |
Having just spent some number of weeks doing a financial services coding effort, I have reached the following conclusions about how to represent and manipulate Money in object-oriented software. I will use Java in the examples but the concepts extend to pretty much anything else out there, strict OO or otherwise.
public class Money { private BigDecimal amt; private String ccode; // .. }
double qq = 1.0 - .9; System.out.println("qq " + qq); // qq 0.09999999999999998<
public class Money { private Money() {} // hide default constructor public Money(int amt, String ccode) { // .. } public Money(long amt, String ccode) { // .. } public Money(String amt, String ccode) { // .. } public Money(BigDecimal amt, String ccode) { // .. } // NO constructor for doubles! double cannot be reliably // ingested to BigDecimal, so just avoid them altogeher. // ... }
public class MoneyUtils { /** * Caller's choice if they want to risk the exception... */ public static Money add(Money a, Money b) throws UnconvertibleCurrencyException { // ... } /** * Fancier versions -- but it can STILL throw an exception in case * the table does not have the necessary conv! */ public static Money add(Money a, Money b, CurrencyConv cc) throws UnconvertibleCurrencyException { // ... } public static Money subtract(Money a, Money b, CurrencyConv cc) throws UnconvertibleCurrencyException { // ... } } // In use: import Money; import MoneyUtils; Money a = new Money(100, "USD"); Money b = new Money(200, "USD"); Money c = MoneyUtils.add(a, b); Money d = new Money(200, "GBP"); CurrencyConv currtbl = factory_or_otherwise_get_it_from_somewhere(); Money e = MoneyUtils.add(c, d, currtbl);
public class Money { public static final String USD = "USD"; public static final String JPY = "JPY"; public static final String EUR = "EUR"; public static final String GBP = "GBP"; //.., } // In use: Money a = new Money(100, Money.USD); Money b = new Money(200, Money.USD); Money c = MoneyUtils.add(a, b); Money d = new Money(200, Money.GBP);
Money m_a = new Money(100, Money.USD); Money m_b = new Money(100, Money.GBP); // Need monies normalized first.... Money m_ba = MoneyUtils.convertTo(m_b, Money.USD, currtbl); // ... before we pull out the actual amount: BigDecimal v_a = m_a.getAmount(); BigDecimal v_ba = m_ba.getAmount(); BigDecimal diff_v = v_a.subtract(v_ba); if(diff_v.compareTo(BigDecimal.ZERO) < 0) { // Do something with a negative amount... } else { // Not negative; rebuild a new Money: BigDecimal c_v = new Money(diff_v, Money.USD); }
Money m_a = new Money(100, Money.USD); BigDecimal v_a = m_a.getAmount(); Money m_b = new Money(100, Money.GBP); BigDecimal v_b = m_b.getAmount(); BigDecimal rate = currtbl.getConvRate(m_a.getCurrencyCode(),m_b.getCurrencyCode()); BigDecimal x = v_b.multiply(rate); // conv GBP to USD BigDecimal diff_v = v_a.subtract(x); if(diff_v.compareTo(BigDecimal.ZERO) < 0) { // Do something with a negative amount... } else { // Not negative; rebuild a new Money: BigDecimal c_v = new Money(diff_v, Money.USD); }
Money m_a = new Money(100, Money.USD); Money m_b = new Money(100, Money.GBP); Money m_diff = MoneyUtils.subtract(m_a, m_b, currtbl); if(m_diff.getAmount().compareTo(BigDecimal.ZERO) < 0) { // (Maybe) do something with negative Money... } else { // NO need to build new Money; m_diff is already good to go! }
/** * Add a,b and return a new Money. * * In the case where currencies are not equal, the CurrencyConv * object will be used to try to perform the conversion. The * currency of Money a is the target and the specific conversion of * the currency of Money b to that of Money a will be used. * If the conversion exists, * the new Money will be returned with currency code * set to that of Money a. For example, * 10 USD + 5 GBP = 17.5 USD (assuming USD<->GBP .6667) * The UnconvertibleCurrencyException will be thrown if a specific * conversion [from B to A] does not exist. */ public static Money add(Money a, Money b, CurrencyConv cc) throws UnconvertibleCurrencyException { // .. }
public void addConvRate(String from, String to, BigDecimal rate, boolean permitInverse)