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
interface
s and composition)
interface
sPaperDocument
reuses Scanner
's
scan()
method
PaperDocument
object to a method
that expects a Printable
interface
s 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
|