1
Peter Coad Object International, Inc. www.oi.com [email protected] 1-919-772-9350 fax -9389 direct line -7734 direct fax -8916
JAVA DESIGNBuilding Better Apps and Applets
Version Date:Jan. 2, 1998
2
Purpose and Agenda Purpose
To gain insights into better design Agenda
1. Design with Composition, Rather than Inheritance. 2. Design with Interfaces. 3. Design with Threads. 4. Design with Notification. 5. Build with Java.
"Building materials profoundly affect design techniques."
3
1. Design with Composition, Rather than Inheritance
Inheritance extends attributes and methods. "What’s the same; what’s different." Weak encapsulation with respect to superclasses Awkward accommodation of change over time
Composition delegates work to other objects. Message-based encapsulation Gracious accommodation of change over time
4
Inheritance: Good Uses (i)
public abstract class MomentInterval extends Object { /*code*/ }public class Reservation extends MomentInterval { /*code*/ }public class Purchase extends MomentInterval { /*code*/ }
total
amount
Purchase
dateTimenumber
MomentInterval
notifyPendingExpiration
dateTimeExpiration
Reservation
9public class Passenger extends Object {
private Vector reservations; /*created by constructor*/ }
Composition
13
public interface IName { public String getName(); public void setName(String aName); }
2. Design with Interfaces A common set of method signatures Interfaces let you connect to and message...
An object in any class that implements that interface Rather than an object in a specific class.
implementer
interface
public Person extends Object implements IName { public String getName() {/*code*/} public void setName(String aName) {/*code*/} }
getNamesetName
IName
IName
Person
14
Why Design with Interfaces?
Abstraction of common method signatures Abstract upwards and avoid method signature overload.
Interaction substitution Interact with objects from one class as if it were an
object from another class. Part substitution
Unplug an object from one class and plug in an object from another class.
15
Interface Strategies (First Set) --Factor Out
a. Strategy: factor-out common method signatures.
b. Strategy: factor-out proxies.
c. Strategy: factor-out by analogy.
d. Strategy: factor-out future expansion.
16
calcTotalcalcTax
quantity
SaleLineItem
howMuch
number
Customer
1 n
1
grandTotalhowMuch
number
Store
1-n
nameaddress
Person
n
1
n
1
n calcTotalcalcTax
dateTime
Sale
11
n
howMany
numberdescriptionprice
Item
a. Common Method Signatures (i)
Strategy: factor-out common method signatures.
a. Common Method Signatures (ii)
ISell
quantity
SaleLineItem
ICount
number
CustomerhowMany
ICount
1
1
n
n
1
calcTotal
ITotal
calcTax
ITax
ITotalICount
number
Store
1-n
nameaddress
Person
ITotalITax
ISell
n
n
1
nISell
dateTime
Sale
11
ICount
numberdescriptionprice
Item
public interface ISell extends ITotal, ITax {}
18
typenumber
Passenger
11INameAddress
typenumber
Passenger
getAddresssetAddress
IAddress
INameAddress
nameaddress
Person
1getNamesetName
IName
INameIAddress
INameAddress
1
INameAddress
nameaddress
Person
Strategy: factor-out proxies.
b. Proxies (i)
19
b. Proxies (ii)
INameIAddress
INameAddress
display
NameAddressUI
n
public class NameAddressUI { private Vector nameAddresses; /*created by constructor*/ public void addNameAddress(INameAddress aNameAddress) { this.nameAddresses.addElement(aNameAddress); } public void display() { Enumeration nameAddressList = this.nameAddresses.elements(); while (nameAddressList.hasMoreElements()) { String nameAddress = (String) nameAddressList.nextElement(); /*display using nameAddress.getName()*/ /*display using nameAddress.getAddress()*/ } } }
20
IDateReserve
FlightDescriptionavailable (date)reserve (date, reserver)cancel (date, reserver)
IDateReserve
hasAvailableSeatreserveSeatcancelSeat
FlightDescription
Strategy: factor-out by analogy.
c. By Analogy (i)
21
c. By Analogy (ii)
IDateReserve
FlightDescription
available (date)reserve (date, reserver)cancel (date, reserver)
IDateReserve
n invokeAvailableinvokeReserveinvokeCancel
DateReserveUI
22
c. By Analogy (iii)
available (date)reserve (date, reserver)cancel (date, reserver)
IDateReserve
reserveResources
DailyWorkOrder
IDateReserve
Equipment
IDateReserve
Workspace
IDateReserve
Worker
n
public class DailyWorkOrder { private Vector dateReservables; /*created by constructor*/ public void addDateReserves(IDateReserve aDateReserve) { this.dateReservables.addElement(aDateReserve); } public void reserveResources() { Enumeration dateReservableList = this.dateReservables.elements(); while (dateReservableList.hasMoreElements()) { IDateReserve dateReservable = (IDateReserve) dateReservablesList.nextElement(); dateReservable.reserve(); } } }
23
d. Future Expansion (i)
Strategy: factor-out for future expansion.
IActivate
Sensor
IActivate
Zone
1
activatedeactivate
IActivaten
Coad notation UML notation
25
d. Future Expansion (iii)
IActivate
Switch
IActivate
RobotArm
IActivate
Motor
nactivatedeactivate
IActivate
IActivate
Sensor
IActivate
Zone
public class Zone { private Vector activatibles; /*created by constructor*/ public void addActivate(IActivate anActivate) { this.activatibles.addElement(anActivate); public void activate() { Enumeration activatableList = this.activatables.elements(); while (activatableList.hasMoreElements()) { IActivatable activatable = (IActivate) activatableList.nextElement(); activatable.activate(); } } }
26
Interface Strategies (Second Set) -- Design-In
e. Strategy: design-in, from features to interfaces.
f. Strategy: design-in, from role to interfaces to proxies.
g. Strategy: design-in, from collections to interfaces.
h. Strategy: design-in, from scenarios to interfaces.
i. Strategy: design-in, from intra-class roles to interfaces.
j. Strategy: design-in, from plug-in methods to interfaces.
27
e. Features to Interfaces (i)
Strategy: design-in, from features to interfaces. Look for a common feature, one you need to provide
in different contexts. Identify a set of common method names that
correspond to that feature. Add an interface. Identify implementers.
Features:Total outstanding balances for a borrowerTotal outstanding balances for an applicant.List accounts and limits for a borrower.List accounts and limits for an applicant.
28
e. Features to Interfaces (ii)
public interface IAccount { public double totalOutstandingBorrowingBalance(); public Enumeration listBorrowingAccountsAndLimits(); }
totalOustandingBorrowingBalancelistBorrowingAccountsAndLimits
IAccount
10-1 getBalance
BorrowingAccount
10-1IAccount
Borrower
IAccount
Applicant
29
f. Role to Interface to Proxies (i)
Strategy: design-in, from role to interface to proxies. Take a role and turn its method signatures into a role-
inspired interface. Let a party or a role offer that same interface by:
Implementing that interface, and Delegating the real work to the original role player.
totalApprovedLimitstotalAvailableLimits
Borrower
30
f. Role to Interface to Proxies (ii)
totalApprovedLimitstotalAvailableLimits
IBorrow
IBorrow
Borrower
totalApprovedLimitstotalAvailableLimits
IBorrow
10-11n IBorrow
Borrower
IBorrow
Applicant
Organization
Person
IBorrow
Party
31
f. Role to Interface to Proxies (iii)
public interface IBorrow { public double totalApprovedLimits(); public double totalAvailableLimits();}public Borrower extends Object implements IBorrow { public double totalApprovedLimits() {/*real work*/} } public double totalAvailableLimits() {/*real work*/}}public Applicant extends Object implements IBorrow { private Borrower borrower; /*add/remove with add/remove methods*/ public double totalApprovedLimits() { return this.borrower. totalApprovedLimits (); /*delegate*/} public double totalAvailableLimits() { return this.borrower. totalAvailableLimits (); /*delegate*/}}
32
g. Collections and Members to Interfaces (i) Strategy: design-in, from collections and members to
interfaces. Does your object hold a collection of other objects? If so:
Consider its potential method signatures. If other collections might offer the same set of method signatures, then
design-in that common interface. Is your object a member within a collection? If so:
If that object needs to provide an interface similar to the collections it is in, then design-in that common interface.
Identify implementers.
33
g. Collections and Members to Interfaces (ii)
totalApprovedLimit
ITotalApprovedLimit
compareAppliedVsApproved
ICompareAppliedVsApproved
1n ITotalApprovedLImitICompareAppliedVsApproved
Approval
ITotalApprovedLimitICompareAppliedVsApproved
Application
34
h. Scenarios to Interfaces(i)
Strategy: design-in, from scenarios to interfaces. Look for similar interaction patterns. Add an interface-implementer column.
Use this naming convention:I<what it does> Implementer
Add an interface: I<what it does>. Identify implementers.
35
h. Scenarios to Interfaces (ii)Name:
( ; risk)
( ; profit)( ; profit)
Assess profit and risk (i).
( ; risk)
Constraints:
assessRisknassessRisk
assessRisknassessRisk
n assessProfitassessProfit
assessProfit
n
assessRisk
Application
n assessRiskassessRisk
assessProfitassessRisk
BorrowingAccount
assessProfitn
assessProfitassessRisk
Applicant
assessRisk
assessRisk
assessProfit
assessProfit
assessProfitassessRisk
Borrower
( ; risk)
Assess profit and risk (ii).Constraints:
( ; profit)
Name:
( ; profit)
( ; risk)assessRisk
assessRisk
assessProfitassessProfit
assessProfit
assessRiskassessRisk
assessProfitassessRisk
IAssessProfitAndRisk Implementer
assessProfitassessRisk
Applicant
assessProfit
36
h. Scenarios to Interfaces (iii)
assessRisk
IAssessRisk
assessProfitIAssessRisk
IAssessProfitAndRisk
1nIAssessProfitAndRisk
BorrowingAccount10-1
1n
IAssessProfitAndRiskassessRisk
Borrower
IAssessRisk
Application
IAssessProfitAndRisk
Applicant
37
i. Intra-Class Roles to Interfaces (i)
Strategy: design-in, from intra-class roles to interfaces. Identify roles that objects within a class can play. Establish an interface for each of those roles. Identify implementers.
38
transferFrom
ITransferDestination
transferTo
ITransferSource
ITransferSourceITransferDestination
Account
i. Intra-Class Roles to Interfaces (ii)
(amount, transferTo ; result)
Constraints:
Name:
(amount ; result)
Transfer from one account to another.
transferTotransferFromtransferFrom
transferFrom
Account [from]
transferTo
Account [to]
transferTo
39
Strategy: design-in, from plug-in methods to interfaces. Look for useful functionality you’d like to "plug in.” Add a plug-point, using an interface. Identify implementers.
j. Plug-In Methods to Interfaces (i)
j. Plug-In Methods to Interfaces (ii)
1 validateTerm
IValidateTerm
validate
Term
Constraints:
( ; result)
Name:
( ; result)
Validate a term.
validateTermvalidatevalidate
validateTerm
IValidateTerm Implementer
validateTerm
validate
Term
public class Term extends Object { private IValidateTerm validater; public int validate() { return validater.validateTerm(); }
public interface IValidateTerm { public int validateTerm(); }
46
Threads and Synchronized Methods (a)
public class ScheduledFlight extends Object { public synchronized Reservation reserve(Passenger aPassenger, Date aDate) {/*code*/} }
(passenger; reservation)
(passenger; reservation)
Constraints:
Name:Reserve space.
(passenger, date; reservation)
ENDSYNCreserveSYNC
reserve
ENDSYNCreserveSYNC
reserve
reserve
FlightDescription
reserve
ENDSYNC
reserve
ScheduledFlight
SYNC
SYNC
reserve
ENDSYNC
reserve
reserve
47
At the start of a sync’d method, just one thread may enter.
That thread can invoke non-syncs no waiting.
That thread can invoke syncs in the same object no waiting.
That thread can invoke syncs in other objects potential waiting, potential for deadlock.
Threads and Synchronized Methods (b)
49
Thread Strategies (a)
"Short Synchronized Methods" Strategy Keep synchronized methods short and to the point.
"Thread Gatekeeper" Strategy Use a thread gatekeeper, an object that permits just
one thread at a time into a collection of cross-messaging objects.
50
Thread Strategies (b)
"Four Thread Designs" Strategy Single Prioritized objects (hi-pri objects, low-pri objects) Prioritized methods (hi-pri methods; low-pri methods) Combo
52
Observer-Observable (inheritance)
public interface Observer {void update (Observable observed; Object argument); }
overly restrictiveinterface--gack!
inheritance of autility function--gack!
java.util
addObserverdeleteObserverdeleteObserversnotifyObservers
Observable
update
Observer
n
methodResultingInStateChggetStatus
status
SpecializedObservable
Observer-Observable (composition model)
public class ObservableComponent extends Object implements IObservableComponent { private Vector myObservers; /*created by constructor*/ public void notifyObservers() { Vector copyMyObservers = (Vector) this.myObservers.clone(); Enumeration myObserverList = this.copyMyObservers.elements(); while (myObserverList.hasMoreElements()) { IObserver observer = (IObserver) myObserverList.nextElement(); observer.update(); } } }
1 [IMyInterface]
n [IObserver] 1 [IObservableComponent]
update
IObserver
IObservablenotifyIObservers
IObservableComponent
addIObserverdeleteIObserverdeleteIObservers
IObservable
getMyValuesetMyValue
IMyInterface
IObserver
MyObserverIObservableComponent
ObservableComponent
IObservableIMyInterface
myValue
MyObservable
public class ThreadedObservableComponent extends Object implements IObservableComponent,Runnable { public void notifyObservers() { this.addToNotificationQueue(observers, observable, changeCode); } public void run() { do // get the next observers-observable-changeCode triad // and notify the observers while this.removeFromNoticationQueue(); } }
Threaded Observer-Observable (model)
run
Runnable
1 [Runnable]1 start
Thread
1 [IMyInterface]
n [IObserver] 1 [IObservableComponent]
update
IObserverIObservablenotifyIObservers
IObservableComponent
addIObserverdeleteIObserverdeleteIObservers
IObservable
getMyValuesetMyValue
IMyInterface
IObserver
MyObserver
IObservableComponentRunnable
ThreadedObservableComponent
IObservableIMyInterface
myValue
MyObservable
Event Source–Event Listener (model)
getSource
EventObject
EventListenerchange
MyEventListener
getMyData
myData
MyEvent
<none>
EventListener
addMyEventListenerremoveMyEventListenerfireMyEvent
MyEventSource
n
java.util
public class MyEventSource extends Object { private Vector myEventListeners; /*created by constructor*/ public void fireMyEvent() { MyEvent myEvent = new MyEvent(); /*then initialize it*/ Vector copyMyEventListeners = (Vector) this.myEventListeners.clone(); Enumeration myEventListenerList = copyMyEventListeners.elements(); MyEventListener myEventListener = (MyEventListener) myEventListenerList.nextElement(); myEventListener.change(myEvent); } } }
naddPropertyChangeListenerremovePropertyChangeListenerfirePropertyChange
PropertyChangeSupport
EventListenerpropertyChange
PropertyChangeListener
sourcepropertyNameoldValuenewValue
PropertyChangeEvent
addPropertyChangeListenerremovePropertyChangeListenerset<propertyName>
MyObject
java.beans
1
Property Change Source-Support-Listener (model)
public class MyObject extends Object { private String name; private PropertyChangeSupport myPropertyChangeSupport; public void setName(String aName) { this.name = aName; myPropertyChangeSupport.firePropertyChange(); } }
better design: define and usean IPropertyChangeSupportinterface
61
5. Build with Java
Design it. Build it with the "Chia Pet” Process
Class H ... Initialize and implement Access Print Equal Test
Acknowledgement:Jill Nicola developed this
process. [Nicola 97]
A "Chia Pet" is a small toy, marketed in various parts of the globe and honorably mentioned in the movie, Wayne's World.
The letters C,I,A,P,E,T represent the stepsin this process.
62
Design It.
getNamesetName
IName
main
TestIndividual
1 0-1 totalOutstandingBalance
IBorrowINameIBorrowequalstoStringbuildTestObject
nameborrower
Individual
-
63
// Individual.javapublic class Individual extends Object implements IName, IBorrow { private String name; //attribute private IBorrow borrower; //object connection public String getName() {/*code*/} //methods public void setName(String aName) {/*code*/} public double totalOutstandingBalance() {/*code*/} }
// IBorrow.javapublic interface IBorrow { public double totalOutstandingBalance(); }
// IName.javapublic interface IName { public String getName(); public void setName (String aName); }
Class
64
// Individual.java (cont.) public Individual(String aName) { this.name = aName; this.borrower = null; }
public String getName() { return this.name; } public void setName(String aName) { this.name = aName; }
public double totalOutstandingBalance() { if (this.borrower != null) return this.borrower.totalOutstandingBalance(); /*delegates*/ else return 0.0d; }
Initialize and Implement
65
// Individual.java (cont.) public String getName() { return this.name; } public void setName(String aName) { this.name = aName; } }
Access
66
Print// Individual.java (cont.) public static int MAXNAMELEN = 100; public String toString() { StringBuffer aStringBuffer = new StringBuffer(MAXNAMELEN); aStringBuffer.append(this.getName()); if (this.borrower != null) aStringBuffer.append(" is an individual and a borrower."); else aStringBuffer.append(" is an individual, not a borrower."); return aStringBuffer.toString(); } }
67
// Individual.java (cont.) public boolean equals(Object anObject) { if ((anObject != null) && (anObject instanceof Individual)) { Individual otherIndividual = (Individual)anObject; return this.name.equals(otherIndividual.name) && this.borrower.equals(otherIndividual.borrower); } else return false; } }
Equal
meaning: does this other object in the same classhave equal attribute values and object connections?
68
// Individual.java (cont.) public static Individual buildTestObject() { return new Individual ("Fred Flinstone”); } }
// TestIndividual.javaimport java.io.*;public class TestIndividual { public static void main(String args[]) { Individual anIndividual = Individual.buildTestObject(); for (int i = 0; i < 5; i++) System.out.println(); System.out.println("This is a test."); System.out.println(anIndividual.toString()); System.out.println("The end."); BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); // A "stream" is a data-holding area with an associated cursor. // An "input stream reader" reads characters from a byte input stream. // A "buffered reader" reads a buffer of characters from a reader. try {String line = in.readLine(); } catch(Exception e) {System.out.println("readLine exception"); } } }
Test
69For more Java Design,
see [Coad97a]
Summary Purpose
To gain insights into better design Agenda
1. Design with Composition, Rather than Inheritance. 2. Design with Interfaces. 3. Design with Threads. 4. Design with Notification. 5. Build with Java.
70
For More... Newsletter
Coad,"The Coad Letter." Free technical newsletter. Subscribe at www.oi.com/newsletters.htm
Books and Workshop Notes [Coad97a] Coad and Mayfield, Java Design: Building Better Apps and Applets.
Prentice Hall, 1997. [Coad97b] Coad, North, Mayfield, Object Models: Strategies, Patterns, and
Applications. Second Edition. Prentice Hall, 1997. [Coad97c] Coad, Peter, How to Build Better Object Models. Workshop Notes.
Object International, 1997. [Nicola97] Nicola, Jill, Java Programming: A Design-Centric Approach.
Workshop Notes. Object International, 1997.
71
Peter Coad Object International, Inc. www.oi.com [email protected] 1-919-772-9350 fax -9389 direct line -7734 direct fax -8916
JAVA DESIGNBuilding Better Apps and Applets