The Artima Developer Community

Designing with Patterns Workshop
Designing with Interfaces

Agenda


Java's Interface


Code Reuse with Composition

  1 package com.artima.examples.account.ex3;
  2
  3 /**
  4 * Represents a bank account with overdraft protection. Instances of this
  5 * class are instantiated with a specified maximum overdraft. If a client
  6 * attempts to withdraw more than the current account balance, the bank may
  7 * loan the amount in excess of the balance to the client. The overdraft
  8 * maximum passed to an <code>OverdraftAccount</code>'s constructor is the
  9 * maximum amount the bank will lend to the client in this manner. When a
 10 * client makes a deposit, the bank will pay itself back first before
 11 * increasing the account's balance.
 12 *
 13 * <p>
 14 * Money is stored in this account in integral units. Clients can use this
 15 * account to store any kind of value, such as money or points, etc. The
 16 * meaning of the integral units stored in this account is a decision of the
 17 * client that instantiates the account. The maximum amount of units that can
 18 * be stored as the current balance of an <code>Account</code> is
 19 * Long.MAX_VALUE.
 20 */
 21 public class OverdraftAccount {
 22
 23     /**
 24     * Helper back-end <code>Account</code> object
 25     */
 26     private Account account = new Account();
 27
 28     /**
 29     * Helper back-end <code>OverdraftEventManager</code> object
 30     */
 31     private OverdraftEventManager eventMan
 32         = new OverdraftEventManager();
 33
 34     /**
 35     * The maximum amount the bank will loan to the client.
 36     */
 37     private final long overdraftMax;
 38
 39     /**
 40     * The current amount the bank has loaned to the client which has not yet
 41     * been repaid. This value must at all times be greater than or equal to
 42     * zero, and less than or equal to <code>overdraftMax</code>. If this
 43     * value is greater than zero, then the balance of the helper
 44     * <code>Account</code> (referenced from the <code>account</code>
 45     * instance variable) must be exactly zero.
 46     */
 47     private long overdraft;
 48
 49     /**
 50     * Constructs a new <code>OverdraftAccount</code> with the passed
 51     * overdraft maximum.
 52     *
 53     * @param overdraftMax the maximum amount the bank will loan to the
 54     *     client
 55     */
 56     public OverdraftAccount(long overdraftMax) {
 57         this.overdraftMax = overdraftMax;
 58     }
 59
 60     /**
 61     * Returns the current overdraft, the amount the bank has loaned to the
 62     * client that has not yet been repaid.
 63     *
 64     * @return the current overdraft
 65     */
 66     public long getOverdraft() {
 67         return overdraft;
 68     }
 69
 70     /**
 71     * Returns the overdraft maximum, the maximum amount the bank will allow
 72     * the client to owe it. For each instance of
 73     * <code>OverdraftAccount</code>, the overdraft maximum is constant.
 74     *
 75     * @return the overdraft maximum
 76     */
 77     public long getOverdraftMax() {
 78         return overdraftMax;
 79     }
 80
 81     /**
 82     * Gets the current balance of this <code>OverdraftAccount</code>.
 83     *
 84     * @return the current balance
 85     */
 86     public long getBalance() {
 87         return account.getBalance();
 88     }
 89
 90     /**
 91     * Withdraws the passed amount from this <code>OverdraftAccount</code>.
 92     * If the passed amount is less than or equal to the current balance, all
 93     * withdrawn funds will be taken from the balance, and the balance will
 94     * be decremented by the passed amount. If the passed amount exceeds the
 95     * current balance, the bank may loan the client the difference. The bank
 96     * will make the loan only if the difference between the passed amount
 97     * and the balance (the shortfall) is less than or equal to the available
 98     * overdraft. The available overdraft is equal to the current overdraft
 99     * (the amount already loaned to the client and not yet repaid),
100     * subtracted from the overdraft maximum, which is passed to the
101     * constructor of any <code>OverdraftAccount</code>.
102     *
103     * <p>
104     * If the passed amount is less than or equal to the current balance, the
105     * <code>withdraw</code> method decrements the current balance by the
106     * passed amount and returns the passed amount. If the passed amount is
107     * greater than the current balance, but the passed amount minus the
108     * current balance is less than or equal to the available overdraft, the
109     * <code>withdraw</code> method sets the current balance to zero, records
110     * the loan, and returns the requested amount. Otherwise, the passed
111     * amount minus the current balance exceeds the available overdraft, so
112     * the <code>withdraw</code> method throws
113     * <code>InsufficientFundsException</code>.
114     *
115     * Subclasses must withdraw at least the passed amount, but may
116     * effectively withdraw more. For example, if a subclass includes a
117     * notion of a withrawal fee, the subclass's implementation of this
118     * method may charge that fee by decrementing it from the account at the
119     * time of withdrawal.
120     *
121     * @param amount amount to withdraw
122     * @return amount withdrawn from the <code>OverdraftAccount</code>
123     * @throws InsufficientFundsException if the
124     *     <code>OverdraftAccount</code> contains insufficient funds for the
125     *     requested withdrawal
126     * @throws IllegalArgumentException if requested withdrawal amount is
127     *     less than or equal to zero.
128     */
129     public long withdraw(long amount) throws InsufficientFundsException {
130
131         if (amount <= 0) {
132             throw new IllegalArgumentException();
133         }
134
135         long bal = account.getBalance();
136         if (bal >= amount) {
137
138             // Balance has sufficient funds, so just take the
139             // money from the balance.
140             return account.withdraw(amount);
141         }
142
143         long shortfall = amount - bal;
144         long extraAvailable = overdraftMax - overdraft;
145
146         if (shortfall > extraAvailable) {
147             throw new InsufficientFundsException(shortfall
148                 - extraAvailable);
149         }
150         overdraft += shortfall;
151         account.withdraw(amount - shortfall);
152
153         OverdraftEvent event = new OverdraftEvent(this, overdraft,
154             shortfall);
155         eventMan.fireOverdraftOccurred(event);
156
157         return amount;
158     }
159
160     /**
161     * Deposits the passed amount into the <code>OverdraftAccount</code>. If
162     * the current overdraft is zero, the balance will be increased by the
163     * passed amount. Otherwise, the bank will attempt to pay off the
164     * overdraft first, before increasing the current balance by the amount
165     * remaining after the overdraft is repaid, if any.
166     *
167     * <p>
168     * For example, if the balance is 0, the overdraft is 100, and the
169     * <code>deposit</code> method is invoked with a passed
170     * <code>amount</code> of 50, the bank would use all 50 of those monetary
171     * units to pay down the overdraft. The overdraft would be reduced to 50
172     * and the balance would remain at 0. If subsequently, the client
173     * deposits another 100 units, the bank would use 50 of those units to
174     * pay off the overdraft loan and direct the remaining 50 into the
175     * balance. The new overdraft would be 0 and the new balance would be
176     * 50.
177     *
178     * Subclasses may effectively deposit more or less than the passed amount
179     * into the <code>Account</code>. For example, if a subclass includes a
180     * notion of funds matching, the subclass implementation of this method
181     * may match some or all of the deposited amount at the time of deposit,
182     * effectively increasing the deposited amount. Or, if a subclass
183     * includes the notion of a deposit fee, the subclass's implementation of
184     * this method may charge that fee by decrementing it from the account at
185     * the time of deposit, effectively reducing the deposited amount.
186     *
187     * @param amount amount to deposit
188     * @throws ArithmeticException if requested deposit would cause the
189     *     balance of this <code>Account</code> to exceed Long.MAX_VALUE.
190     * @throws IllegalArgumentException if requested withdrawal amount is
191     *     less than or equal to zero.
192     */
193     public void deposit(long amount) {
194
195         if (amount <= 0) {
196             throw new IllegalArgumentException();
197         }
198
199         if (overdraft > 0) {
200
201             long amountRepaid = 0;
202
203             if (amount < overdraft) {
204                 amountRepaid = amount;
205                 overdraft -= amount;
206             }
207             else {
208                 long diff = amount - overdraft;
209                 amountRepaid = diff;
210                 overdraft = 0;
211                 account.deposit(diff);
212             }
213
214             OverdraftEvent event = new OverdraftEvent(this, overdraft,
215                 amountRepaid);
216             eventMan.fireOverdraftRepaid(event);
217         }
218         else {
219             account.deposit(amount);
220         }
221     }
222
223     /**
224     * Adds the specified overdraft listener to receive overdraft events from
225     * this <code>OverdraftAccount</code>. If <code>l</code> is
226     * <code>null</code>, no exception is thrown and no action is performed.
227     * If <code>l</code> is already registered as a listener, no action is
228     * performed.
229     *
230     * @param l the <code>OverdraftEventListener</code> to add
231     */
232     public void addOverdraftListener(OverdraftListener l) {
233
234         eventMan.addOverdraftListener(l);
235     }
236
237     /**
238     * Removes the specified overdraft listener so that it no longer receives
239     * overdraft events from this <code>OverdraftAccount</code>. This method
240     * performs no function, nor does it throw an exception, if the listener
241     * specified by the argument was not previously added to this component.
242     * If <code>l</code> is <code>null</code>, no exception is thrown and no
243     * action is performed.
244     *
245     * @param l the <code>OverdraftEventListener</code> to remove
246     */
247     public void removeOverdraftListener(OverdraftListener l) {
248
249         eventMan.removeOverdraftListener(l);
250     }
251 }


 1 package com.artima.examples.account.ex3;
 2
 3 /**
 4 * Represents a bank account. Money is stored in this account in integral
 5 * units. Clients can use this account to store any kind of value, such as
 6 * money or points, etc. The meaning of the integral units stored in this
 7 * account is a decision of the client that instantiates the account. The
 8 * maximum amount of units that can be stored as the current balance of an
 9 * <code>Account</code> is Long.MAX_VALUE.
10 */
11 public class Account {
12
13     /**
14     * The current balance
15     */
16     private long balance;
17
18     /**
19     * Withdraws exactly the passed amount from the <code>Account</code>.
20     * Subclasses must withdraw at least the passed amount, but may
21     * effectively withdraw more. For example, if a subclass includes a
22     * notion of a withrawal fee, the subclass's implementation of this
23     * method may charge that fee by decrementing it from the account at the
24     * time of withdrawal.
25     *
26     * @param amount amount to withdraw
27     * @return amount withdrawn from the <code>Account</code>
28     * @throws InsufficientFundsException if the <code>Account</code>
29     *     contains insufficient funds for the requested withdrawal
30     * @throws IllegalArgumentException if the passed <code>amount</code> to
31     *    withdraw is less than or equal to zero.
32     */
33     public long withdraw(long amount)
34         throws InsufficientFundsException {
35
36         if (amount <= 0) {
37             throw new IllegalArgumentException();
38         }
39
40         if (amount > balance) {
41             throw new InsufficientFundsException(amount - balance);
42         }
43
44         balance -= amount;
45         return amount;
46     }
47
48     /**
49     * Deposits exactly the passed amount into the <code>Account</code>.
50     * Subclasses may effectively deposit more or less than the passed amount
51     * into the <code>Account</code>. For example, if a subclass includes a
52     * notion of funds matching, the subclass implementation of this method
53     * may match some or all of the deposited amount at the time of deposit,
54     * effectively increasing the deposited amount. Or, if a subclass
55     * includes the notion of a deposit fee, the subclass's implementation of
56     * this method may charge that fee by decrementing it from the account at
57     * the time of deposit, effectively reducing the deposited amount.
58     *
59     * @param amount amount to deposit
60     * @throws ArithmeticException if requested deposit would cause the
61     *     balance of this <code>Account</code> to exceed Long.MAX_VALUE.
62     * @throws IllegalArgumentException if requested deposit is less than
63     *     or equal to zero.
64     */
65     public void deposit(long amount) {
66
67         if (amount <= 0) {
68             throw new IllegalArgumentException();
69         }
70
71         long newBal = balance + amount;
72
73         if (newBal < 0) {
74             throw new ArithmeticException();
75         }
76
77         balance = newBal;
78     }
79
80     /**
81     * Gets the current balance of this <code>Account</code>
82     *
83     * @return the current balance
84     */
85     public long getBalance() {
86         return balance;
87     }
88 }
89

  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 OverdraftEventManager {
 15
 16     /**
 17     * Unsynchronized <code>HashSet</code> to which listeners are added and
 18     * removed via the synchronized methods <code>addOverdraftListener</code>
 19     * and <code>removeOverdraftListener</code> methods.
 20     */
 21     private HashSet listeners = new HashSet();
 22
 23     /**
 24     * Clone of the <code>listeners</code> <code>HashSet</code>, which is
 25     * used by the <code>fireOverdraftOccurred</code> and
 26     * <code>fireOverdraftRepaid</code> methods to propagate events. This
 27     * <code>HashSet</code> always contains a most recent snapshot of the
 28     * <code>listeners</code> <code>HashSet</code>, but this
 29     * <code>HashSet</code> is never modified, only replaced. Because this
 30     * <code>HashSet</code> is never modified, the fire methods can iterate
 31     * through the set without synchronization. This implementation approach
 32     * is geared towards providing optimum performance for the expected run
 33     * time usage in which adding and removing listeners happens less
 34     * frequently than firing events to those listeners.
 35     */
 36     private Set listenersClone = new HashSet();
 37
 38     /**
 39     * Constructs a new <code>OverdraftEventManager</code>. The
 40     * <code>OverdraftEventManager</code> starts its life with an empty
 41     * listeners list.
 42     */
 43     public OverdraftEventManager() {
 44     }
 45
 46     /**
 47     * Adds the specified overdraft listener to receive overdraft events. If
 48     * <code>l</code> is <code>null</code>, no exception is thrown and no
 49     * action is performed. If <code>l</code> is already registered as a
 50     * listener, no action is performed.
 51     *
 52     * @param l the <code>OverdraftEventListener</code> to add
 53     */
 54     public synchronized void addOverdraftListener(OverdraftListener l) {
 55
 56         listeners.add(l);
 57         listenersClone = (Set) listeners.clone();
 58     }
 59
 60     /**
 61     * Removes the specified overdraft listener so that it no longer receives
 62     * overdraft events. This method performs no function, nor does it throw
 63     * an exception, if the listener specified by the argument was not
 64     * previously added to this component. If <code>l</code> is
 65     * <code>null</code>, no exception is thrown and no action is performed.
 66     *
 67     * @param l the <code>OverdraftEventListener</code> to remove
 68     */
 69     public synchronized void removeOverdraftListener(OverdraftListener l) {
 70
 71         listeners.remove(l);
 72         listenersClone = (Set) listeners.clone();
 73     }
 74
 75     /**
 76     * Fires overdraftOccurred events to registered listeners.
 77     *
 78     * @param event the <code>OverdraftEvent</code> to propagate
 79     */
 80     public void fireOverdraftOccurred(OverdraftEvent event) {
 81
 82         Iterator it = listenersClone.iterator();
 83         while (it.hasNext()) {
 84             OverdraftListener l = (OverdraftListener) it.next();
 85             l.overdraftOccurred(event);
 86         }
 87     }
 88
 89     /**
 90     * Fires overdraftRepaid events to registered listeners.
 91     *
 92     * @param event the <code>OverdraftEvent</code> to propagate
 93     */
 94     public void fireOverdraftRepaid(OverdraftEvent event) {
 95
 96         Iterator it = listenersClone.iterator();
 97         while (it.hasNext()) {
 98             OverdraftListener l = (OverdraftListener) it.next();
 99             l.overdraftRepaid(event);
100         }
101     }
102 }

Full Blown Multiple Inheritance


Polymorphism with Pure ABCs


Multiple Inheritance Usefulness


Composition with interfaces

 1 package com.artima.examples.account.ex4;
 2
 3 /**
 4 * Represents a bank account. Money is stored in this account in integral
 5 * units. Clients can use this account to store any kind of value, such as
 6 * money or points, etc. The meaning of the integral units stored in this
 7 * account is a decision of the client that instantiates the account. The
 8 * maximum amount of units that can be stored as the current balance of an
 9 * <code>Account</code> is Long.MAX_VALUE.
10 */
11 public interface Account {
12
13     /**
14     * Withdraws exactly the passed amount from the <code>Account</code>.
15     * Subclasses must withdraw at least the passed amount, but may
16     * effectively withdraw more. For example, if a subclass includes a
17     * notion of a withrawal fee, the subclass's implementation of this
18     * method may charge that fee by decrementing it from the account at the
19     * time of withdrawal.
20     *
21     * @param amount amount to withdraw
22     * @return amount withdrawn from the <code>Account</code>
23     * @throws InsufficientFundsException if the <code>Account</code>
24     *     contains insufficient funds for the requested withdrawal
25     * @throws IllegalArgumentException if the passed <code>amount</code> to
26     *    withdraw is less than or equal to zero.
27     */
28     long withdraw(long amount) throws InsufficientFundsException;
29
30     /**
31     * Deposits exactly the passed amount into the <code>Account</code>.
32     * Subclasses may effectively deposit more or less than the passed amount
33     * into the <code>Account</code>. For example, if a subclass includes a
34     * notion of funds matching, the subclass implementation of this method
35     * may match some or all of the deposited amount at the time of deposit,
36     * effectively increasing the deposited amount. Or, if a subclass
37     * includes the notion of a deposit fee, the subclass's implementation of
38     * this method may charge that fee by decrementing it from the account at
39     * the time of deposit, effectively reducing the deposited amount.
40     *
41     * @param amount amount to deposit
42     * @throws ArithmeticException if requested deposit would cause the
43     *     balance of this <code>Account</code> to exceed Long.MAX_VALUE.
44     * @throws IllegalArgumentException if requested deposit is less than
45     *     or equal to zero.
46     */
47     void deposit(long amount);
48
49     /**
50     * Gets the current balance of this <code>Account</code>.
51     *
52     * @return the current balance
53     */
54     long getBalance();
55 }
56


 1 package com.artima.examples.account.ex4;
 2
 3 /**
 4 * A generator of <code>OverdraftEvent</code>s. Classes that implement this
 5 * interface manages the registration and unregistration of
 6 * <code>OverdraftListener</code>s and the firing of
 7 * <code>OverdraftEvent</code>s.
 8 *
 9 * @author Bill Venners
10 */
11 public interface OverdraftEventGenerator {
12
13     /**
14     * Adds the specified overdraft listener to receive overdraft events. If
15     * <code>l</code> is <code>null</code>, no exception is thrown and no
16     * action is performed. If <code>l</code> is already registered as a
17     * listener, no action is performed.
18     *
19     * @param l the <code>OverdraftEventListener</code> to add
20     */
21     void addOverdraftListener(OverdraftListener l);
22
23     /**
24     * Removes the specified overdraft listener so that it no longer receives
25     * overdraft events. This method performs no function, nor does it throw
26     * an exception, if the listener specified by the argument was not
27     * previously added to this component. If <code>l</code> is
28     * <code>null</code>, no exception is thrown and no action is performed.
29     *
30     * @param l the <code>OverdraftEventListener</code> to remove
31     */
32     void removeOverdraftListener(OverdraftListener l);
33 }


  1 package com.artima.examples.account.ex4;
  2
  3 /**
  4 * Represents a bank account with overdraft protection. Instances of this
  5 * class are instantiated with a specified maximum overdraft. If a client
  6 * attempts to withdraw more than the current account balance, the bank may
  7 * loan the amount in excess of the balance to the client. The overdraft
  8 * maximum passed to an <code>OverdraftAccount</code>'s constructor is the
  9 * maximum amount the bank will lend to the client in this manner. When a
 10 * client makes a deposit, the bank will pay itself back first before
 11 * increasing the account's balance.
 12 *
 13 * <p>
 14 * Money is stored in this account in integral units. Clients can use this
 15 * account to store any kind of value, such as money or points, etc. The
 16 * meaning of the integral units stored in this account is a decision of the
 17 * client that instantiates the account. The maximum amount of units that can
 18 * be stored as the current balance of an <code>OverdraftAccount</code> is
 19 * Long.MAX_VALUE.
 20 */
 21 public class OverdraftAccount implements Account, OverdraftEventGenerator {
 22
 23     /**
 24     * Helper back-end <code>BasicAccount</code> object
 25     */
 26     private BasicAccount account = new BasicAccount();
 27
 28     /**
 29     * Helper back-end <code>OverdraftEventManager</code> object
 30     */
 31     private OverdraftEventManager eventMan
 32         = new OverdraftEventManager();
 33
 34     /**
 35     * The maximum amount the bank will loan to the client.
 36     */
 37     private final long overdraftMax;
 38
 39     /**
 40     * The current amount the bank has loaned to the client which has not yet
 41     * been repaid. This value must at all times be greater than or equal to
 42     * zero, and less than or equal to <code>overdraftMax</code>. If this
 43     * value is greater than zero, then the balance of the helper
 44     * <code>BasicAccount</code> (referenced from the <code>account</code>
 45     * instance variable) must be exactly zero.
 46     */
 47     private long overdraft;
 48
 49     /**
 50     * Constructs a new <code>OverdraftAccount</code> with the passed
 51     * overdraft maximum.
 52     *
 53     * @param overdraftMax the maximum amount the bank will loan to the
 54     *     client
 55     */
 56     public OverdraftAccount(long overdraftMax) {
 57         this.overdraftMax = overdraftMax;
 58     }
 59
 60     /**
 61     * Returns the current overdraft, the amount the bank has loaned to the
 62     * client that has not yet been repaid.
 63     *
 64     * @return the current overdraft
 65     */
 66     public long getOverdraft() {
 67         return overdraft;
 68     }
 69
 70     /**
 71     * Returns the overdraft maximum, the maximum amount the bank will allow
 72     * the client to owe it. For each instance of
 73     * <code>OverdraftAccount</code>, the overdraft maximum is constant.
 74     *
 75     * @return the overdraft maximum
 76     */
 77     public long getOverdraftMax() {
 78         return overdraftMax;
 79     }
 80
 81     /**
 82     * Gets the current balance of this <code>OverdraftAccount</code>.
 83     *
 84     * @return the current balance
 85     */
 86     public long getBalance() {
 87         return account.getBalance();
 88     }
 89
 90     /**
 91     * Withdraws the passed amount from this <code>OverdraftAccount</code>.
 92     * If the passed amount is less than or equal to the current balance, all
 93     * withdrawn funds will be taken from the balance, and the balance will
 94     * be decremented by the passed amount. If the passed amount exceeds the
 95     * current balance, the bank may loan the client the difference. The bank
 96     * will make the loan only if the difference between the passed amount
 97     * and the balance (the shortfall) is less than or equal to the available
 98     * overdraft. The available overdraft is equal to the current overdraft
 99     * (the amount already loaned to the client and not yet repaid),
100     * subtracted from the overdraft maximum, which is passed to the
101     * constructor of any <code>OverdraftAccount</code>.
102     *
103     * <p>
104     * If the passed amount is less than or equal to the current balance, the
105     * <code>withdraw</code> method decrements the current balance by the
106     * passed amount and returns the passed amount. If the passed amount is
107     * greater than the current balance, but the passed amount minus the
108     * current balance is less than or equal to the available overdraft, the
109     * <code>withdraw</code> method sets the current balance to zero, records
110     * the loan, and returns the requested amount. Otherwise, the passed
111     * amount minus the current balance exceeds the available overdraft, so
112     * the <code>withdraw</code> method throws
113     * <code>InsufficientFundsException</code>.
114     *
115     * Subclasses must withdraw at least the passed amount, but may
116     * effectively withdraw more. For example, if a subclass includes a
117     * notion of a withrawal fee, the subclass's implementation of this
118     * method may charge that fee by decrementing it from the account at the
119     * time of withdrawal.
120     *
121     * @param amount amount to withdraw
122     * @return amount withdrawn from the <code>OverdraftAccount</code>
123     * @throws InsufficientFundsException if the
124     *     <code>OverdraftAccount</code> contains insufficient funds for the
125     *     requested withdrawal
126     * @throws IllegalArgumentException if requested withdrawal amount is
127     *     less than or equal to zero.
128     */
129     public long withdraw(long amount) throws InsufficientFundsException {
130
131         if (amount <= 0) {
132             throw new IllegalArgumentException();
133         }
134
135         long bal = account.getBalance();
136         if (bal >= amount) {
137
138             // Balance has sufficient funds, so just take the
139             // money from the balance.
140             return account.withdraw(amount);
141         }
142
143         long shortfall = amount - bal;
144         long extraAvailable = overdraftMax - overdraft;
145
146         if (shortfall > extraAvailable) {
147             throw new InsufficientFundsException(shortfall
148                 - extraAvailable);
149         }
150         overdraft += shortfall;
151         account.withdraw(amount - shortfall);
152
153         OverdraftEvent event = new OverdraftEvent(this, overdraft,
154             shortfall);
155         eventMan.fireOverdraftOccurred(event);
156
157         return amount;
158     }
159
160     /**
161     * Deposits the passed amount into the <code>OverdraftAccount</code>. If
162     * the current overdraft is zero, the balance will be increased by the
163     * passed amount. Otherwise, the bank will attempt to pay off the
164     * overdraft first, before increasing the current balance by the amount
165     * remaining after the overdraft is repaid, if any.
166     *
167     * <p>
168     * For example, if the balance is 0, the overdraft is 100, and the
169     * <code>deposit</code> method is invoked with a passed
170     * <code>amount</code> of 50, the bank would use all 50 of those monetary
171     * units to pay down the overdraft. The overdraft would be reduced to 50
172     * and the balance would remain at 0. If subsequently, the client
173     * deposits another 100 units, the bank would use 50 of those units to
174     * pay off the overdraft loan and direct the remaining 50 into the
175     * balance. The new overdraft would be 0 and the new balance would be
176     * 50.
177     *
178     * Subclasses may effectively deposit more or less than the passed amount
179     * into the <code>OverdraftAccount</code>. For example, if a subclass
180     * includes a notion of funds matching, the subclass implementation of
181     * this method may match some or all of the deposited amount at the time
182     * of deposit, effectively increasing the deposited amount. Or, if a
183     * subclass includes the notion of a deposit fee, the subclass's
184     * implementation of this method may charge that fee by decrementing it
185     * from the account at the time of deposit, effectively reducing the
186     * deposited amount.
187     *
188     * @param amount amount to deposit
189     * @throws ArithmeticException if requested deposit would cause the
190     *     balance of this <code>OverdraftAccount</code> to exceed
191     *     Long.MAX_VALUE.
192     * @throws IllegalArgumentException if requested withdrawal amount is
193     *     less than or equal to zero.
194     */
195     public void deposit(long amount) {
196
197         if (amount <= 0) {
198             throw new IllegalArgumentException();
199         }
200
201         if (overdraft > 0) {
202
203             long amountRepaid = 0;
204
205             if (amount < overdraft) {
206                 amountRepaid = amount;
207                 overdraft -= amount;
208             }
209             else {
210                 long diff = amount - overdraft;
211                 amountRepaid = diff;
212                 overdraft = 0;
213                 account.deposit(diff);
214             }
215
216             OverdraftEvent event = new OverdraftEvent(this, overdraft,
217                 amountRepaid);
218             eventMan.fireOverdraftRepaid(event);
219         }
220         else {
221             account.deposit(amount);
222         }
223     }
224
225     /**
226     * Adds the specified overdraft listener to receive overdraft events from
227     * this <code>OverdraftAccount</code>. If <code>l</code> is
228     * <code>null</code>, no exception is thrown and no action is performed.
229     * If <code>l</code> is already registered as a listener, no action is
230     * performed.
231     *
232     * @param l the <code>OverdraftEventListener</code> to add
233     */
234     public void addOverdraftListener(OverdraftListener l) {
235
236         eventMan.addOverdraftListener(l);
237     }
238
239     /**
240     * Removes the specified overdraft listener so that it no longer receives
241     * overdraft events from this <code>OverdraftAccount</code>. This method
242     * performs no function, nor does it throw an exception, if the listener
243     * specified by the argument was not previously added to this component.
244     * If <code>l</code> is <code>null</code>, no exception is thrown and no
245     * action is performed.
246     *
247     * @param l the <code>OverdraftEventListener</code> to remove
248     */
249     public void removeOverdraftListener(OverdraftListener l) {
250
251         eventMan.removeOverdraftListener(l);
252     }
253 }


 1 package com.artima.examples.account.ex4;
 2
 3 /**
 4 * Represents a bank account. Money is stored in this account in integral
 5 * units. Clients can use this account to store any kind of value, such as
 6 * money or points, etc. The meaning of the integral units stored in this
 7 * account is a decision of the client that instantiates the account. The
 8 * maximum amount of units that can be stored as the current balance of an
 9 * <code>BasicAccount</code> is Long.MAX_VALUE.
10 */
11 public class BasicAccount implements Account {
12
13     /**
14     * The current balance
15     */
16     private long balance;
17
18     /**
19     * Withdraws exactly the passed amount from the
20     * <code>BasicAccount</code>. Subclasses must withdraw at least the
21     * passed amount, but may effectively withdraw more. For example, if a
22     * subclass includes a notion of a withrawal fee, the subclass's
23     * implementation of this method may charge that fee by decrementing it
24     * from the account at the time of withdrawal.
25     *
26     * @param amount amount to withdraw
27     * @return amount withdrawn from the <code>BasicAccount</code>
28     * @throws InsufficientFundsException if the <code>BasicAccount</code>
29     *     contains insufficient funds for the requested withdrawal
30     * @throws IllegalArgumentException if the passed <code>amount</code> to
31     *    withdraw is less than or equal to zero.
32     */
33     public long withdraw(long amount) throws InsufficientFundsException {
34
35         if (amount <= 0) {
36             throw new IllegalArgumentException();
37         }
38
39         if (amount > balance) {
40             throw new InsufficientFundsException(amount - balance);
41         }
42
43         balance -= amount;
44         return amount;
45     }
46
47     /**
48     * Deposits exactly the passed amount into the <code>BasicAccount</code>.
49     * Subclasses may effectively deposit more or less than the passed amount
50     * into the <code>BasicAccount</code>. For example, if a subclass
51     * includes a notion of funds matching, the subclass implementation of
52     * this method may match some or all of the deposited amount at the time
53     * of deposit, effectively increasing the deposited amount. Or, if a
54     * subclass includes the notion of a deposit fee, the subclass's
55     * implementation of this method may charge that fee by decrementing it
56     * from the account at the time of deposit, effectively reducing the
57     * deposited amount.
58     *
59     * @param amount amount to deposit
60     * @throws ArithmeticException if requested deposit would cause the
61     *     balance of this <code>BasicAccount</code> to exceed
62     *     Long.MAX_VALUE.
63     * @throws IllegalArgumentException if requested deposit is less than
64     *     or equal to zero.
65     */
66     public void deposit(long amount) {
67
68         if (amount <= 0) {
69             throw new IllegalArgumentException();
70         }
71
72         long newBal = balance + amount;
73
74         if (newBal < 0) {
75             throw new ArithmeticException();
76         }
77
78         balance = newBal;
79     }
80
81     /**
82     * Gets the current balance of this <code>BasicAccount</code>.
83     *
84     * @return the current balance
85     */
86     public long getBalance() {
87         return balance;
88     }
89 }
90


Why are interfaces so useful?


Interfaces and C++


Discussion


How to use interfaces


A Noun interface


An Adjective interface


An Tag interface


Pulling interfaces out of Thin Air


Discussion


Service Decoupling


Restricting Semantics


Discussion


Convenience Implementations


Discussion


Abstract Classes


Discussion


Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use