'How to Build Better Object Models'

Download Report

Transcript 'How to Build Better Object Models'

JAVA DESIGN
Building Better Apps and Applets
 Peter Coad
 Object
International, Inc.
 www.oi.com [email protected]
 1-919-772-9350 fax -9389
 direct line -7734 direct fax -8916
Version Date:
Jan. 2, 1998
1
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."
2
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
 Message-based
work to other objects.
encapsulation
 Gracious accommodation of change over time
3
Inheritance: Good Uses (i)
MomentInterval
dateTime
number
Reservation
4
Purchase
dateTimeExpiration
amount
notifyPendingExpiration
total
public abstract class MomentInterval extends Object { /*code*/ }
public class Reservation extends MomentInterval { /*code*/ }
public class Purchase extends MomentInterval { /*code*/ }
Inheritance: Good Uses (ii)
5
Inheritance: Problems (i)
6
Inheritance: Problems (ii)
7
Inheritance: When to Use It
8
Composition
9
public class Passenger extends Object {
private Vector reservations; /*created by constructor*/ }
Composition and Change (i)
10
Composition and Change (ii)
11
Combo
12
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.
IN a m e
g e tN a m e
s e tN a m e
public interface IName {
public String getName();
public void setName(String aName); }
interface
Person
IName
13
implementer
public Person extends Object implements IName {
public String getName() {/*code*/}
public void setName(String aName) {/*code*/} }
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.
14
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.
15
a. Common Method Signatures (i)
 Strategy: factor-out common method signatures.
Person
name
address
n
1
number
howMuch
Store
Sale
Customer
number
dateTime
n
1
calcTotal
calcTax
1
n
grandTotal
howMuch
n
1-n
1
1
Item
SaleLineItem
quantity
calcTotal
calcTax
16
1
n
number
description
price
howMany
a. Common Method Signatures (ii)
Customer
Person
name
address
n
1
number
ICount
Sale
n
1
dateTime
ISell
1
n
1-n
Store
ICount
number
howMany
ITotal
ICount
n
ITotal
calcTotal
ITax
1
1
calcTax
Item
SaleLineItem
quantity
ISell
1
n
number
description
price
ISell
ITotal
ITax
ICount
public interface ISell extends ITotal, ITax {}
b. Proxies (i)
 Strategy: factor-out proxies.
Person
name
address
INameAddress
1
1
Passenger
type
number
IName
getName
setName
IAddress
getAddress
setAddress
Person
name
address
INameAddress
18
1
1
Passenger
type
number
INameAddress
INameAddress
IName
IAddress
b. Proxies (ii)
INameAddress
NameAddressUI
display
19
n
IName
IAddress
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()*/ } } }
c. By Analogy (i)
 Strategy: factor-out by analogy.
FlightDescription
hasAvailableSeat
reserveSeat
cancelSeat
FlightDescription
IDateReserve
20
IDateReserve
available (date)
reserve (date, reserver)
cancel (date, reserver)
c. By Analogy (ii)
DateReserveUI
invokeAvailable
invokeReserve
invokeCancel
n
IDateReserve
available (date)
reserve (date, reserver)
cancel (date, reserver)
FlightDescription
IDateReserve
21
c. By Analogy (iii)
DailyWorkOrder
reserveResources
22
n
IDateReserve
available (date)
reserve (date, reserver)
cancel (date, reserver)
Equipment
Worker
Workspace
IDateReserve
IDateReserve
IDateReserve
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(); } } }
d. Future Expansion (i)
 Strategy: factor-out for future expansion.
Zone
IActivate
IActivate
n
activate
deactivate
1
Sensor
IActivate
Coad notation
23
UML notation
d. Future Expansion (ii)
IActivate
Zone
IActivate
n
activate
deactivate
Sensor
IActivate
24
d. Future Expansion (iii)
IActivate
Zone
IActivate
25
activate
deactivate
n
Sensor
Motor
IActivate
IActivate
RobotArm
IActivate
Switch
IActivate
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(); } } }
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.
26
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.
27
Features:
Total outstanding balances for a borrower
Total outstanding balances for an applicant.
List accounts and limits for a borrower.
List accounts and limits for an applicant.
e. Features to Interfaces (ii)
IAccount
totalOustandingBorrowingBalance
listBorrowingAccountsAndLimits
Applicant
IAccount
28
BorrowingAccount
Borrower
0-1
1
IAccount
0-1
1
getBalance
public interface IAccount {
public double totalOutstandingBorrowingBalance();
public Enumeration listBorrowingAccountsAndLimits(); }
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 roleinspired 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.

Borrower
29
totalApprovedLimits
totalAvailableLimits
f. Role to Interface to Proxies (ii)
Borrower
IBorrow
totalApprovedLimits
totalAvailableLimits
IBorrow
Party
IBorrow
Person
30
Borrower
Applicant
n
Organization
1
IBorrow
0-1
1
IBorrow
IBorrow
totalApprovedLimits
totalAvailableLimits
f. Role to Interface to Proxies (iii)
31
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*/}
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
32
implementers.
g. Collections and Members to Interfaces (ii)
ITotalApprovedLimit
totalApprovedLimit
ICompareAppliedVsApproved
compareAppliedVsApproved
Approval
Application
ITotalApprovedLimit
ICompareAppliedVsApproved
33
n
1
ITotalApprovedLImit
ICompareAppliedVsApproved
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.
34
h. Scenarios to Interfaces (ii)
Applicant
Application
assessProfit
assessRisk
assessRisk
Borrower
BorrowingAccount
assessProfit
assessRisk
assessProfit
assessRisk
assessProfit
( ; profit)
( ; profit)
assessProfit
n
assessProfit
assessRisk
n
Name:
Assess profit and risk (i).
Constraints:
( ; risk)
( ; risk)
assessRisk
assessRisk
n
Applicant
assessProfit
assessRisk
IAssessProfitAndRisk Implementer
assessProfit
assessRisk
assessProfit
Name:
Assess profit and risk (ii).
Constraints:
assessProfit
( ; profit)
( ; profit)
assessRisk
( ; risk)
( ; risk)
assessRisk
35
assessRisk
h. Scenarios to Interfaces (iii)
Application
Applicant
n
1
0-1
1
IAssessProfitAndRisk
IAssessRisk
IAssessProfitAndRisk
assessProfit
IAssessRisk
Borrower
IAssessProfitAndRisk
assessRisk
36
IAssessRisk
assessRisk
BorrowingAccount
n
1
IAssessProfitAndRisk
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.
37
i. Intra-Class Roles to Interfaces (ii)
Account
ITransferSource
ITransferDestination
Account [from]
Account [to]
transferFrom
transferTo
transferFrom
transferTo
38
ITransferSource
transferTo
ITransferDestination
transferFrom
Name:
Transfer from one account to another.
Constraints:
(amount, transferTo ; result)
(amount ; result)
j. Plug-In Methods to Interfaces (i)
 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.
39
j. Plug-In Methods to Interfaces (ii)
Term
validate
Term
validate
1
IValidateTerm
validateTerm
IValidateTerm Implementer
validateTerm
validate
validateTerm
public interface IValidateTerm {
public int validateTerm(); }
Name:
Validate a term.
Constraints:
( ; result)
( ; result)
public class Term extends Object {
private IValidateTerm validater;
public int validate() {
return validater.validateTerm(); }
3. Design with Threads
 A thread is
41
a stream of program execution.
Multiple Threads
42
this.mainThread = new Thread (this);
this.mainThread.start();
Why Threads
43
Threads and Shared Values (a)
44
Threads and Shared Values (b)
45
Threads and Synchronized Methods (a)
FlightDescription
ScheduledFlight
reserve
reserve
reserve
Name:
Reserve space.
Constraints:
(passenger, date; reservation)
SYNC
reserve
ENDSYNC
(passenger; reservation)
SYNC
reserve
ENDSYNC
(passenger; reservation)
reserve
public class ScheduledFlight extends Object {
public synchronized Reservation reserve(Passenger aPassenger, Date aDate) {/*code*/} }
46
Threads and Synchronized Methods (b)
 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.
47
Threads and Synchronized Methods (c)
.
48
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 crossmessaging objects.
49
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
50
4. Design with Notification
51
Observer-Observable (inheritance)
inheritance of a
utility function--gack!
overly restrictive
interface--gack!
Observable
addObserver
deleteObserver
deleteObservers
notifyObservers
Observer
n
update
java.util
SpecializedObservable
status
methodResultingInStateChg
getStatus
52
public interface Observer {
void update (Observable observed; Object argument); }
Observer-Observable (composition sketch)
53
Observer-Observable (composition model)
MyObservable
myValue
IObservable
IMyInterface
ObservableComponent
1 [IObservableComponent]
IObservableComponent
n [IObserver]
MyObserver
IObserver
1 [IMyInterface]
IObservable
addIObserver
deleteIObserver
deleteIObservers
IMyInterface
getMyValue
setMyValue
IObservableComponent
IObservable
notifyIObservers
IObserver
update
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(); } } }
Threaded Observer-Observable (sketch)
55
Threaded Observer-Observable (model)
Thread
ThreadedObservableComponent
MyObservable
myValue
IObservable
IMyInterface
1 [IObservableComponent]
IObservableComponent
Runnable
1
1 [Runnable]
n [IObserver]
start
MyObserver
IObserver
1 [IMyInterface]
IMyInterface
getMyValue
setMyValue
IObservable
addIObserver
deleteIObserver
deleteIObservers
IObservableComponent
IObservable
notifyIObservers
Runnable
run
IObserver
update
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(); } }
Event Source–Event Listener (sketch)
57
Event Source–Event Listener (model)
EventObject
EventListener
<none>
java.util
getSource
MyEvent
myData
getMyData
MyEventSource
addMyEventListener
removeMyEventListener
fireMyEvent
n
MyEventListener
EventListener
change
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); } } }
Property Change Source-Support-Listener (sketch)
59
Property Change Source-Support-Listener (model)
PropertyChangeEvent
source
propertyName
oldValue
newValue
PropertyChangeSupport
addPropertyChangeListener
removePropertyChangeListener
firePropertyChange
1
PropertyChangeListener
n
EventListener
propertyChange
java.beans
better design: define and use
an IPropertyChangeSupport
interface
MyObject
addPropertyChangeListener
removePropertyChangeListener
set<propertyName>
public class MyObject extends Object {
private String name;
private PropertyChangeSupport myPropertyChangeSupport;
public void setName(String aName) {
this.name = aName;
myPropertyChangeSupport.firePropertyChange(); } }
5. Build with Java
 Design
it.
 Build it with the "Chia Pet” Process J
 Class
H
...
 Initialize and implement
 Access
 Print
 Equal
 Test
61
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 steps
in this process.
Acknowledgement:
Jill Nicola developed this
process. [Nicola 97]
Design It.
Individual
name
borrower
TestIndividual
main
62
IName
getName
setName
1
-
IName
IBorrow
equals
toString
buildTestObject
0-1
IBorrow
totalOutstandingBalance
Class
// Individual.java
public 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.java
public interface IBorrow {
public double totalOutstandingBalance(); }
// IName.java
public interface IName {
public String getName();
public void setName (String aName); }
63
Initialize and Implement
// 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; }
64
Access
// Individual.java (cont.)
public String getName() {
return this.name; }
public void setName(String aName) {
this.name = aName; } }
65
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(); } }
66
meaning: does this other object in the same class
have equal attribute values and object connections?
Equal
// 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; } }
67
Test
// Individual.java (cont.)
public static Individual buildTestObject() {
return new Individual ("Fred Flinstone”); } }
// TestIndividual.java
import 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(); }
68 catch(Exception e) {System.out.println("readLine exception"); } } }
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.
69
For more Java Design,
see [Coad97a]
For More...
 Newsletter

Coad,"The Coad Letter." Free technical newsletter. Subscribe at
www.oi.com/newsletters.htm
 Books and




70
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.
JAVA DESIGN
Building Better Apps and Applets
 Peter Coad
 Object
International, Inc.
 www.oi.com [email protected]
 1-919-772-9350 fax -9389
 direct line -7734 direct fax -8916
71