View Javadoc
1   package junit.samples.money;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   /**
7    * A MoneyBag defers exchange rate conversions. For example adding
8    * 12 Swiss Francs to 14 US Dollars is represented as a bag
9    * containing the two Monies 12 CHF and 14 USD. Adding another
10   * 10 Swiss francs gives a bag with 22 CHF and 14 USD. Due to
11   * the deferred exchange rate conversion we can later value a
12   * MoneyBag with different exchange rates.
13   *
14   * A MoneyBag is represented as a list of Monies and provides
15   * different constructors to create a MoneyBag.
16   */
17  public class MoneyBag implements IMoney {
18      private List<Money> fMonies = new ArrayList<Money>(5);
19  
20      public static IMoney create(IMoney m1, IMoney m2) {
21          MoneyBag result = new MoneyBag();
22          m1.appendTo(result);
23          m2.appendTo(result);
24          return result.simplify();
25      }
26  
27      public IMoney add(IMoney m) {
28          return m.addMoneyBag(this);
29      }
30  
31      public IMoney addMoney(Money m) {
32          return MoneyBag.create(m, this);
33      }
34  
35      public IMoney addMoneyBag(MoneyBag s) {
36          return MoneyBag.create(s, this);
37      }
38  
39      void appendBag(MoneyBag aBag) {
40          for (Money each : aBag.fMonies) {
41              appendMoney(each);
42          }
43      }
44  
45      void appendMoney(Money aMoney) {
46          if (aMoney.isZero()) return;
47          IMoney old = findMoney(aMoney.currency());
48          if (old == null) {
49              fMonies.add(aMoney);
50              return;
51          }
52          fMonies.remove(old);
53          Money sum = (Money) old.add(aMoney);
54          if (sum.isZero()) {
55              return;
56          }
57          fMonies.add(sum);
58      }
59  
60      @Override
61      public boolean equals(Object anObject) {
62          if (isZero()) {
63              if (anObject instanceof IMoney) {
64                  return ((IMoney) anObject).isZero();
65              }
66          }
67  
68          if (anObject instanceof MoneyBag) {
69              MoneyBag aMoneyBag = (MoneyBag) anObject;
70              if (aMoneyBag.fMonies.size() != fMonies.size()) {
71                  return false;
72              }
73  
74              for (Money each : fMonies) {
75                  if (!aMoneyBag.contains(each)) {
76                      return false;
77                  }
78              }
79              return true;
80          }
81          return false;
82      }
83  
84      private Money findMoney(String currency) {
85          for (Money each : fMonies) {
86              if (each.currency().equals(currency)) {
87                  return each;
88              }
89          }
90          return null;
91      }
92  
93      private boolean contains(Money m) {
94          Money found = findMoney(m.currency());
95          if (found == null) return false;
96          return found.amount() == m.amount();
97      }
98  
99      @Override
100     public int hashCode() {
101         int hash = 0;
102         for (Money each : fMonies) {
103             hash ^= each.hashCode();
104         }
105         return hash;
106     }
107 
108     public boolean isZero() {
109         return fMonies.size() == 0;
110     }
111 
112     public IMoney multiply(int factor) {
113         MoneyBag result = new MoneyBag();
114         if (factor != 0) {
115             for (Money each : fMonies) {
116                 result.appendMoney((Money) each.multiply(factor));
117             }
118         }
119         return result;
120     }
121 
122     public IMoney negate() {
123         MoneyBag result = new MoneyBag();
124         for (Money each : fMonies) {
125             result.appendMoney((Money) each.negate());
126         }
127         return result;
128     }
129 
130     private IMoney simplify() {
131         if (fMonies.size() == 1) {
132             return fMonies.iterator().next();
133         }
134         return this;
135     }
136 
137     public IMoney subtract(IMoney m) {
138         return add(m.negate());
139     }
140 
141     @Override
142     public String toString() {
143         StringBuilder sb = new StringBuilder();
144         sb.append("{");
145         for (Money each : fMonies) {
146             sb.append(each);
147         }
148         sb.append("}");
149         return sb.toString();
150     }
151 
152     public void appendTo(MoneyBag m) {
153         m.appendBag(this);
154     }
155 }