quarta-feira, 19 de novembro de 2008

Quantity and Measure: Money Toolbox

Quantity and Measure: Money Toolbox

It's not possible to develop a business application without having to handle money amounts. Ultimately "business" means "making money", right ?. Some businesses have money as the primary product (aka banks) where it is even more important to control it correctly.

Money is - put simple - an amount (a number) of currency. Well, this is the hook we need to integrate money into the Quantity and Measure toolbox. Money is a measure of currency amount.

Money

Money is a well know design pattern. Everybody knows that doubles and floats do not cut it when you want to handle money. Standard java offers the possibility to use BigDecimal as a value object for representing money, but a simpler ( more strong typed) solution exists.
So we start by considering that money has is a finite amount. It is not possible to represent an 1/3 with money. It simply isn't. This show us that all operations with money are integer operations.

Because all money operations with money are integer operations we can use a long to store the amount. Now you may be thinking: "what about the cents?". Well we multiply the real amount by a power of 10, the result will be a integer value. When the amount is asked for, we divide by that same factor before returning. Very simple.

Using the long is very cleaver but need to multiply by a factor that converts fractional amounts into integer amounts. By what power of 10 is that factor ? Well, for dollar, that uses two decimals for cents, it would be 102=100. And for Yen ? Well, Yen doesn't have a fractional part! Yes, not all currencies have the same fractional number of digits. Some have none, and some have more than two. In standard java we use getDefaultFractionDigits() from Currency to discover the fraction digits for each currency.

Currency

Currency is not the unit for money amounts in a way similar as meter is the unit of length. It's a unit. There are, in fact, several possible units as for length there are several. The main difference is that for physical units that are units more used that other. The SI uses meter, and any one using the SI uses the same unit. For money this is not possible. there is no standard currency. So each country adopts it's own currency, but because countries trade with each other they need to convert values between the different currencies.

Currency conversion is not, in essence, different from length unit conversion (say meter to mile), but in practice, all other units have constant conversion rates, currency does not.
Information about the current and historical currency rates is an asset , an so, many companies sell access to query this information. (nowadays mostly over web services). So, another basic operation in the money toolbox is currency conversion, i.e. convert money with amount expressed in a currency,to money with amount expressed in another.

In standard java we use getDefaultFractionDigits() from Currency to discover the fraction digits for each currency , but MiddleHeaven's Currency is an Unit. How can we handle this. MiddleHeaven resolves this by providing Currency as and abstract class. This way we can implement other currencies. Some applications (specially finance related), may establish different sets of properties for they currency object. MiddleHeaven provides ISOCurrency that is in fact based on standard java Currency class.

Currencies are further related to countries, cultures, and treaties (like euro) and change over time. A country can have more that one official currency and can have more that one currency over the years. So handling all these details for currencies is tied to tracking all these changes and possibilities.

Model

Money class represent money amounts and permits arithmetic operations. Some operations are special, like division, and there is no operation to multiply a Money for Money ( there is no Money squared). You can multiply it, however, by any real number. Money is an Amount witch is a Quantity that can perform group operations (addition and subtraction) Currency is the measurable. ISOCurrency is the default implementation for Currency

The MoneyConverter is a simple interface to convert money between currencies that is used together with MoneyConverterService. We will cover services later on and we will be back to this toolbox for examples.

Use

This example demonstrates a unit test that performs operations with money. Money object need a currency to be specified, and as default we can specify it by means of a simple string with the currency ISO code.
01
02 Money a = Money.money ( 100 , "USD" ) ;
03 Money b = Money.money ( 230 , "USD" ) ;
04 Money t = Money.money ( 330 , "USD" ) ;
05
06 Money c = Money.money ( 330 , "EUR" ) ;
07
08 Money m = a.plus ( b ) ;
09
10 assertEquals ( t, m ) ;
11
12 // money are equal if both amount and currency are equal
13 assertFalse ( t.equals ( c )) ;
14
15 // can only add money of the same currency
16 // will throw IncompatibleUnitsException
17 t.plus ( c ) ;
18
19
20 // eu is not an ISO code
21 // will throw IllegalArgumentException
22
23 Money.money ( 330 , "EU" ) ; // eu is not a iso code
24
25
26 // multiply by a real
27 Real n = Real.valueOf ( 3 ) ;
28 Money y = t.over ( n ) ;
29 assertEquals ( Money.money ( 110 , "USD" ) , y ) ;
30
31

Code 1: Example of use for Money

Nenhum comentário:

Postar um comentário