The Artima Developer Community
Sponsored Link

Interface Design by Bill Venners
Appreciate the significance of the interface

Advertisement

Interface Design | Contents | Previous | Next

Java's Interface


Code Reuse with Composition

 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 }

Full Blown Multiple Inheritance


The ABC Alternative


Multiple Inheritance Usefulness


Composition with interfaces





Why are interfaces so useful?


Interfaces and C++

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



Google
  Web Artima.com   
Copyright © 1996-2017 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us