|
|
|
Sponsored Link •
|
|
Advertisement
|
interface.
OverdraftAccount enlists the help of Account and
OverdraftEventGenerator
OverdraftAccount reuses (delegates to) Account's
getBalance() method
OverdraftAccount object to a method
that expects an Account
1 package com.artima.examples.account.ex3;
2
3 /**
4 * Represents a bank account. Money is stored in this account
5 * in integral units. Clients can use this account to store
6 * any kind of value, such as money or points, etc. The meaning
7 * of the integral units stored in this account is a decision
8 * of the client that instantiates the account. The maximum
9 * amount of units that can be stored as the current balance of
10 * an <code>Account</code> is Long.MAX_VALUE.
11 */
12 public class Account {
13
14 /**
15 * The current balance
16 */
17 private long balance;
18
19 /**
20 * Withdraws exactly the passed amount from the
21 * <code>Account</code>. Subclasses must withdraw
22 * at least the passed amount, but may effectively withdraw more.
23 * For example, if a subclass includes the notion of
24 * a withrawal fee, the subclass's implementation of
25 * this method may charge that fee by decrementing it
26 * from the account at the time of withdrawal.
27 *
28 * @param amount amount to withdraw
29 * @returns amount withdrawn from the <code>Account</code>
30 * @throws InsufficientFundsException if the <code>Account</code>
31 * contains insufficient funds for the requested withdrawal
32 */
33 public long withdraw(long amount)
34 throws InsufficientFundsException {
35
36 if (amount > balance) {
37 throw new InsufficientFundsException(
38 amount - balance);
39 }
40
41 balance -= amount;
42 return amount;
43 }
44
45 /**
46 * Deposits exactly the passed amount into the <code>Account</code>.
47 * Subclasses may effectively deposit more or less than the passed
48 * amount into the <code>Account</code>. For example, if a subclass
49 * includes the notion of funds matching, the subclass implementation
50 * of this method may match some or all of the deposited amount at
51 * the time of deposit, effectively increasing the deposited amount.
52 * Or, if a subclass includes the notion of
53 * a deposit fee, the subclass's implementation of
54 * this method may charge that fee by decrementing it
55 * from the account at the time of withdrawal, effectively reducing
56 * the deposited amount.
57 *
58 * @param amount amount to deposit
59 * @throws ArithmeticException if requested deposit would cause the
60 * balance of this <code>Account</code> to exceed Long.MAX_VALUE.
61 */
62 public void deposit(long amount) {
63
64 // TO DO: Check for overflow
65 balance += amount;
66 }
67
68 /**
69 * Gets the current balance of this <code>Account</code>
70 *
71 * @returns the current balance
72 */
73 public long getBalance() {
74 return balance;
75 }
76 }
77
1 package com.artima.examples.account.ex3;
2
3 import java.util.Set;
4 import java.util.Iterator;
5 import java.util.HashSet;
6
7 /**
8 * A class that manages registration and unregistration of
9 * <code>OverdraftListener</code>s and the firing of
10 * <code>OverdraftEvent</code>s.
11 *
12 * @author Bill Venners
13 */
14 class OverdraftEventGenerator {
15
16 private Set listeners = new HashSet();
17
18 /**
19 * Constructs a new <code>OverdraftEventGenerator</code>. The
20 * <code>OverdraftEventGenerator</code> starts its life with an
21 * empty listeners list.
22 */
23 public OverdraftEventGenerator() {
24 }
25
26 /**
27 * Adds the specified overdraft listener to receive overdraft events.
28 * If <code>l</code> is <code>null</code>, no exception
29 * is thrown and no action is performed. If <code>l</code> is already registered
30 * as a listener, no action is performed.
31 */
32 public synchronized void addOverdraftListener(OverdraftListener l) {
33
34 listeners.add(l);
35 }
36
37 /**
38 * Removes the specified overdraft listener so that it no longer
39 * receives overdraft events. This method
40 * performs no function, nor does it throw an exception, if the listener
41 * specified by the argument was not previously added to this
42 * component. If <code>l</code> is <code>null</code>, no exception is
43 * thrown and no action is performed.
44 */
45 public synchronized void removeOverdraftListener(OverdraftListener l) {
46
47 listeners.remove(l);
48 }
49
50 /**
51 * Fires overdraftOccurred events to registered listeners.
52 *
53 * @param event the <code>OverdraftEvent</code> to propagate
54 */
55 void fireOverdraftOccurred(OverdraftEvent event) {
56
57 Iterator it = listeners.iterator();
58 while (it.hasNext()) {
59 OverdraftListener l = (OverdraftListener) it.next();
60 l.overdraftOccurred(event);
61 }
62 }
63
64 /**
65 * Fires overdraftRepaid events to registered listeners.
66 *
67 * @param event the <code>OverdraftEvent</code> to propagate
68 */
69 void fireOverdraftRepaid(OverdraftEvent event) {
70
71 Iterator it = listeners.iterator();
72 while (it.hasNext()) {
73 OverdraftListener l = (OverdraftListener) it.next();
74 l.overdraftRepaid(event);
75 }
76 }
77 }
1 package com.artima.examples.account.ex3;
2
3 /**
4 * Represents a bank account with overdraft protection. Instances
5 * of this class are instantiated with a specified maximum
6 * overdraft. If a client attempts to withdraw more than the
7 * current account balance, the bank may loan the amount in
8 * excess of the balance to the client. The overdraft maximum
9 * passed to an <code>OverdraftAccount</code>'s constructor
10 * is the maximum amount the bank will lend to the client in
11 * this manner. When a client makes a deposit, the bank will
12 * pay itself back first before increasing the account's balance.
13 *
14 * <p>
15 * Money is stored in this account in integral units. Clients
16 * can use this account to store any kind of value, such as money
17 * or points, etc. The meaning of the integral units stored in
18 * this account is a decision of the client that instantiates the
19 * account. The maximum amount of units that can be stored as
20 * the current balance of an <code>Account</code> is Long.MAX_VALUE.
21 */
22 public class OverdraftAccount {
23
24 /**
25 * Helper back-end object
26 */
27 private Account account = new Account();
28 private OverdraftEventGenerator eventGen = new OverdraftEventGenerator();
29
30 /**
31 * The maximum amount the bank will loan to the client.
32 */
33 private final long overdraftMax;
34
35 /**
36 * The current amount the bank has loaned to the client
37 * which has not yet been repaid. This must be zero to
38 * overdraftMax.
39 */
40 private long overdraft;
41
42 /**
43 * Constructs a new <code>OverdraftAccount</code> with the
44 * passed <code>overdraftMax</code>.
45 *
46 * @param overdraftMax the maximum amount the bank will loan
47 * to the client
48 */
49 public OverdraftAccount(long overdraftMax) {
50 this.overdraftMax = overdraftMax;
51 }
52
53 /**
54 * Adds the specified overdraft listener to receive overdraft events
55 * from this <code>OverdraftAccount</code>. If <code>l</code> is <code>null</code>, no exception
56 * is thrown and no action is performed. If <code>l</code> is already registered
57 * as a listener, no action is performed.
58 */
59 public synchronized void addOverdraftListener(OverdraftListener l) {
60
61 eventGen.addOverdraftListener(l);
62 }
63
64 /**
65 * Removes the specified overdraft listener so that it no longer
66 * receives overdraft events from this <code>OverdraftAccount</code>. This method
67 * performs no function, nor does it throw an exception, if the listener
68 * specified by the argument was not previously added to this
69 * component. If <code>l</code> is <code>null</code>, no exception is
70 * thrown and no action is performed.
71 */
72 public synchronized void removeOverdraftListener(OverdraftListener l) {
73
74 eventGen.removeOverdraftListener(l);
75 }
76
77 /**
78 * Returns the current overdraft, the amount the bank has
79 * loaned to the client that has not yet been repaid.
80 *
81 * @returns the current overdraft
82 */
83 public long getOverdraft() {
84 return overdraft;
85 }
86
87 /**
88 * Returns the overdraft maximum, the maximum amount the
89 * bank will allow the client to owe it. For each instance
90 * of <code>OverdraftAccount</code>, the overdraft maximum
91 * is constant.
92 *
93 * @returns the overdraft maximum
94 */
95 public long getOverdraftMax() {
96 return overdraftMax;
97 }
98
99 /**
100 * Gets the current balance of this <code>OverdraftAccount</code>
101 *
102 * @returns the current balance
103 */
104 public long getBalance() {
105 return account.getBalance();
106 }
107
108 /**
109 * Withdraws exactly the passed amount from the
110 * <code>Account</code>. If the passed amount is
111 * less than or equal to the current balance, all withdrawn
112 * funds will be taken from the balance, and the balance
113 * will be decremented by the passed amount. If the passed amount
114 * exceeds the current balance, the bank may loan the client the
115 * difference. The bank will make the loan only if the difference
116 * between the passed amount and the balance is less than or equal to
117 * the available overdraft. The available overdraft is equal to
118 * the current overdraft (the amount already loaned to the client and
119 * not yet repaid), subtracted from the overdraft maximum, which
120 * is passed to the constructor of any <code>OverdraftAccount</code>.
121 *
122 * <p>
123 * If the passed amount less the current balance is less than or equal
124 * to the available overdraft, the <code>withdraw</code> method returns
125 * the requested amount, sets the current balance to zero, and records
126 * the loan. Otherwise, if the passed amount less the current balance
127 * exceeds the available overdraft, the <code>withdraw</code> method throws
128 * <code>InsufficientFundsException</code>.
129 *
130 * @param amount amount to withdraw
131 * @returns amount withdrawn from the <code>Account</code>
132 * @throws InsufficientFundsException if the <code>Account</code>
133 * contains insufficient funds for the requested withdrawal
134 */
135 public long withdraw(long amount)
136 throws InsufficientFundsException {
137
138 long balance = account.getBalance();
139 if (balance >= amount) {
140
141 // Balance has sufficient funds, just take the
142 // money from the balance.
143 balance -= amount;
144 return amount;
145 }
146
147 long shortfall = amount - balance;
148 long extraAvailable = overdraftMax - overdraft;
149
150 if (shortfall > extraAvailable) {
151 throw new InsufficientFundsException(shortfall - extraAvailable);
152 }
153 overdraft += shortfall;
154 account.withdraw(amount - shortfall);
155
156 eventGen.fireOverdraftOccurred(new OverdraftEvent(this, overdraft));
157
158 return amount;
159 }
160
161 /**
162 * Deposits exactly the passed amount into the <code>Account</code>.
163 * If the current overdraft is zero, the balance will be increased
164 * by the passed amount. Otherwise, the bank will attempt to pay
165 * off the overdraft first, before increasing the current balance
166 * by the amount remaining after the overdraft is repaid, if any.
167 *
168 * <p>
169 * For example, if the balance is 200, the overdraft is 100, and the
170 * <code>deposit</code> method is invoked with a passed <code>amount</code>
171 * of 50, the bank would use all 50 of those monetary units to pay down
172 * the overdraft. The overdraft would be reduced to 50 and the balance would
173 * remain at 200. If subsequently, the client deposits another 100 units,
174 * the bank would use 50 of those units to pay off the overdraft loan and
175 * direct the remaining 50 into the balance. The new overdraft would
176 * be 0 and the new balance would be 250.
177 *
178 * @param amount amount to deposit
179 * @throws ArithmeticException if requested deposit would cause the
180 * balance of this <code>Account</code> to exceed Long.MAX_VALUE.
181 */
182 public void deposit(long amount) {
183 if (overdraft > 0) {
184 if (amount < overdraft) {
185 overdraft -= amount;
186 }
187 else {
188 long diff = amount - overdraft;
189 overdraft = 0;
190 account.deposit(diff);
191 }
192
193 eventGen.fireOverdraftRepaid(new OverdraftEvent(this, overdraft));
194 }
195 else {
196 account.deposit(amount);
197 }
198 }
199 }
OverdraftAccount reuses (inherits) Account's
getBalance() method
OverdraftAccount object to a method
that expects an Account
OverdraftAccount can't reuse Account's
getBalance() method, because it is abstract
OverdraftAccount object to a method
that expects an Account
Useful in 5% of design situations
Useful in 50% of design situations
interface
interfaces and composition)
interfaces
PaperDocument reuses Scanner's
scan() method
PaperDocument object to a method
that expects a Printable
interfaces so useful?interface can be implemented in many ways:
Doesn't make sense for ArrayList to be superclass of LinkedList, because LinkedList has no common implementation interest with ArrayList. Class extension makes sense when there is common implementation interest -- you can see it as factoring out common code into one place. But you can do the same kind of factoring with composition. And, like the factoring of moving code to data described in Guideline 2, you do this factoring ahead of time in an oo design.
|
Sponsored Links
|