710 likes | 825 Views
JAVA DESIGN Building Better Apps and Applets. Peter Coad Object International, Inc. www.oi.com pc@oi.com 1-919-772-9350 fax -9389 direct line -7734 direct fax -8916. Version Date: Jan. 2, 1998. Purpose and Agenda. Purpose To gain insights into better design Agenda
E N D
JAVA DESIGNBuilding Better Apps and Applets • Peter Coad • Object International, Inc. • www.oi.com pc@oi.com • 1-919-772-9350 fax -9389 • direct line -7734 direct fax -8916 Version Date: Jan. 2, 1998
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."
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
Inheritance: Good Uses (i) MomentInterval dateTime number Reservation Purchase dateTimeExpiration amount notifyPendingExpiration total publicabstractclass MomentInterval extends Object { /*code*/ } publicclass Reservation extends MomentInterval { /*code*/ } publicclass Purchase extends MomentInterval { /*code*/ }
Composition publicclass Passenger extends Object { private Vector reservations; /*created by constructor*/ }
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. publicinterface IName { public String getName(); publicvoid setName(String aName); } interface public Person extends Object implements IName { public String getName() {/*code*/} publicvoid setName(String aName) {/*code*/} } Person IName implementer
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.
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.
a. Common Method Signatures (i) • Strategy: factor-out common method signatures. Person Store Sale Customer name number dateTime number address n 1 n 1 1 n grandTotal calcTotal howMuch howMuch calcTax n 1-n 1 1 Item SaleLineItem number quantity description 1 n calcTotal price calcTax howMany
a. Common Method Signatures (ii) Store ICount Customer Person Sale number howMany number name dateTime n 1 n 1 1 n ITotal address ICount ISell ICount ITotal 1-n calcTotal n ITax 1 calcTax 1 Item ISell SaleLineItem number ITotal quantity description ITax 1 n price ISell ICount publicinterface ISell extends ITotal, ITax {}
b. Proxies (i) • Strategy: factor-out proxies. Passenger Person type name IName 1 1 number address getName INameAddress setName IAddress getAddress setAddress INameAddress Person Passenger IName name type IAddress address number 1 1 INameAddress INameAddress
b. Proxies (ii) INameAddress NameAddressUI IName n IAddress display publicclass NameAddressUI { private Vector nameAddresses; /*created by constructor*/ publicvoid addNameAddress(INameAddress aNameAddress) { this.nameAddresses.addElement(aNameAddress); } publicvoid display() { Enumeration nameAddressList = this.nameAddresses.elements(); while (nameAddressList.hasMoreElements()) { StringnameAddress = (String) nameAddressList.nextElement(); /*display using nameAddress.getName()*/ /*display using nameAddress.getAddress()*/ } } }
c. By Analogy (i) • Strategy: factor-out by analogy. FlightDescription hasAvailableSeat reserveSeat cancelSeat IDateReserve FlightDescription available (date) reserve (date, reserver) IDateReserve cancel (date, reserver)
c. By Analogy (ii) DateReserveUI IDateReserve available (date) invokeAvailable n reserve (date, reserver) invokeReserve cancel (date, reserver) invokeCancel FlightDescription IDateReserve
c. By Analogy (iii) IDateReserve DailyWorkOrder available (date) reserve (date, reserver) n reserveResources cancel (date, reserver) Equipment Worker Workspace IDateReserve IDateReserve IDateReserve publicclass DailyWorkOrder { private Vector dateReservables; /*created by constructor*/ publicvoid addDateReserves(IDateReserve aDateReserve) { this.dateReservables.addElement(aDateReserve); } publicvoid 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 UML notation
d. Future Expansion (ii) IActivate Zone activate deactivate n IActivate Sensor IActivate
d. Future Expansion (iii) IActivate Zone activate deactivate n IActivate Sensor Motor RobotArm Switch IActivate IActivate IActivate IActivate publicclass Zone { private Vector activatibles; /*created by constructor*/ publicvoid addActivate(IActivate anActivate) { this.activatibles.addElement(anActivate); publicvoid 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.
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 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 BorrowingAccount Applicant Borrower 0-1 1 0-1 1 getBalance IAccount IAccount publicinterface IAccount { publicdouble 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 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. Borrower totalApprovedLimits totalAvailableLimits
f. Role to Interface to Proxies (ii) Borrower IBorrow totalApprovedLimits totalAvailableLimits IBorrow Borrower Party Applicant 0-1 1 n 1 IBorrow IBorrow IBorrow Person Organization IBorrow totalApprovedLimits totalAvailableLimits
f. Role to Interface to Proxies (iii) • publicinterface IBorrow { • publicdouble totalApprovedLimits(); • publicdouble totalAvailableLimits(); • } • public Borrower extends Object implements IBorrow { • publicdouble totalApprovedLimits() {/*real work*/} } • publicdouble totalAvailableLimits() {/*real work*/} • } • public Applicant extends Object implements IBorrow { • private Borrower borrower; /*add/remove with add/remove methods*/ • publicdouble totalApprovedLimits() { • returnthis.borrower. totalApprovedLimits (); /*delegate*/} • publicdouble totalAvailableLimits() { • returnthis.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 implementers.
g. Collections and Members to Interfaces (ii) ITotalApprovedLimit totalApprovedLimit ICompareAppliedVsApproved compareAppliedVsApproved Approval Application n 1 ITotalApprovedLImit ITotalApprovedLimit ICompareAppliedVsApproved 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.
h. Scenarios to Interfaces (ii) Name: Assess profit and risk (i). Applicant Application Borrower BorrowingAccount Constraints: assessProfit assessRisk assessProfit assessProfit assessRisk assessRisk assessRisk assessProfit assessProfit ( ; profit) assessProfit assessProfit ( ; profit) n n assessProfit assessProfit assessRisk assessRisk ( ; risk) n n assessRisk assessRisk ( ; risk) assessRisk assessRisk n n assessRisk assessRisk Name: Assess profit and risk (ii). Applicant IAssessProfitAndRisk Implementer Constraints: assessProfit assessProfit assessRisk assessRisk assessProfit assessProfit ( ; profit) assessProfit assessProfit ( ; profit) assessRisk assessRisk ( ; risk) assessRisk assessRisk ( ; risk)
h. Scenarios to Interfaces (iii) IAssessProfitAndRisk IAssessRisk Application assessProfit assessRisk IAssessRisk Applicant IAssessRisk n 1 IAssessProfitAndRisk Borrower 0-1 1 BorrowingAccount n 1 IAssessProfitAndRisk IAssessProfitAndRisk assessRisk
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.
i. Intra-Class Roles to Interfaces (ii) ITransferSource Account transferTo ITransferSource ITransferDestination ITransferDestination transferFrom Name: Transfer from one account to another. Account [from] Account [to] Constraints: transferFrom transferTo transferFrom transferFrom (amount, transferTo ; result) transferTo transferTo (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.
j. Plug-In Methods to Interfaces (ii) Term IValidateTerm 1 validateTerm validate Name: Validate a term. Term IValidateTerm Implementer Constraints: validate validateTerm validate validate ( ; result) validateTerm validateTerm ( ; result) • publicclass Term extends Object { • private IValidateTerm validater; • publicint validate() { • return validater.validateTerm(); } • publicinterface IValidateTerm { • publicint validateTerm(); }
3. Design with Threads • A thread is a stream of program execution.
Multiple Threads this.mainThread = new Thread (this); this.mainThread.start();
Threads and Synchronized Methods (a) Name: Reserve space. FlightDescription ScheduledFlight Constraints: reserve reserve reserve reserve (passenger, date; reservation) SYNC SYNC reserve reserve (passenger; reservation) ENDSYNC ENDSYNC reserve reserve SYNC SYNC reserve reserve (passenger; reservation) ENDSYNC ENDSYNC publicclass ScheduledFlight extends Object { publicsynchronized Reservation reserve(Passenger aPassenger, Date aDate) {/*code*/} }
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.
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.
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