71
Peter Coad Object International, Inc. www.oi.com [email protected] 1-919-772-9350 fax -9389 direct line -7734 direct fax - 8916 JAVA DESIGN Building Better Apps and Applets Version Date: Jan. 2, 1998

1 u Peter Coad u Object International, Inc. u [email protected] u 1-919-772-9350 fax -9389 u direct line -7734 direct fax -8916 JAVA DESIGN Building

  • View
    214

  • Download
    1

Embed Size (px)

Citation preview

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

5

Inheritance: Good Uses (ii)

6

Inheritance: Problems (i)

7

Inheritance: Problems (ii)

8

Inheritance: When to Use It

9public class Passenger extends Object {

private Vector reservations; /*created by constructor*/ }

Composition

10

Composition and Change (i)

11

Composition and Change (ii)

12

Combo

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

24

d. Future Expansion (ii)

IActivate

Sensor

IActivate

Zone

activatedeactivate

IActivate

n

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(); }

41

3. Design with Threads A thread is a stream of program execution.

42this.mainThread = new Thread (this);this.mainThread.start();

Multiple Threads

43

Why Threads

44

Threads and Shared Values (a)

45

Threads and Shared Values (b)

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)

48

Threads and Synchronized Methods (c)

.

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

51

4. Design with Notification

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

53

Observer-Observable (composition sketch)

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

55

Threaded Observer-Observable (sketch)

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

57

Event Source–Event Listener (sketch)

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); } } }

59

Property Change Source-Support-Listener (sketch)

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