Creting Flexible Interfces 1
Requests, not Objects Domin objects re esy to find but they re not t the design center of your ppliction. Insted, they re trp for the unwry. Sequence digrms re vehicle for exposing, experimenting with, nd ultimtely defining [ the requests tht pss between objects, tht is, ]... interfces. I need to send this messge, who should respond to it? is the first step [ towrds more flexible pplictions ]. You don t send messges becuse you hve objects, you hve objects becuse you send messges. 2
moe Customer suitble_trips (on_dte, of_difficulty, need bike) clss moe Customer suitble_trip (on_dte, of difficulty) for ech trip found clss clss Bicycle moe Customer clss suitble_bicycle (trip_dte, route type) ce digrm. Figure 4.3 A simple sequence digrm. moe Customer clss clss Bicycle Figure 4.4 Moe tlks to trip nd bicycle. 3
Mechnic bicycles for ech bicycle clen bicycle(bike) pump tires(bike) lube chin(bike) check brkes(bike) Mechnic Figure 4.5 A tells Mechnic how to prepre ech Bicycle. 4
the novice designer. Figure 4.5 is quite procedurl. A tells Mechnic how to prepre Bicycle, lmost s if were the min progrm nd Mechnic bunch of cllble functions. In this design, is the only object tht knows exctly how to prepre bike; getting bike prepred requires using or duplicting the code. s context is lrge, s is Mechnic s public interfce. These two clsses re not islnds with bridges between them, they re insted single, woven cloth. Mny new object-oriented progrmmers strt out working just this wy, writing procedurl code. It s inevitble; this style closely mirrors the best prctices of their former procedurl lnguges. Unfortuntely, coding in procedurl style defets the purpose of object orienttion. It reintroduces the exct mintennce issues tht OOP is designed to void. Figure 4.6 is more object-oriented. Here, sks to prepre 5
Mechnic Mechnic bicycles bicycles for ech bicycle clen bicycle(bike) pump tires(bike) for ech bicycle prepre bicycle(bike) clen_bicycle(bike) lube chin(bike) etc... check brkes(bike) Mechnic Figure 4.5 A tells Mechnic how to prepre ech Bicycle. Mechnic Figure 4.6 A sks Mechnic to prepre ech Bicycle. 6
Figure 4.6 is more object-oriented. Here, sks Mechnic to prepre Bicycle. s context is reduced, nd Mechnic s public interfce is smller. Additionlly, Mechnic s public interfce is now something tht ny object my profitbly use; you don t need to prepre bike. These objects now communicte in few well-defined wys; they re less coupled nd more esily reusble. This style of coding plces the responsibilities in the correct objects, gret improvement, but continues to require tht hve more context thn is necessry. still knows tht it holds onto n object tht cn respond to prepre_bicycle, nd it must lwys hve this object. Figure 4.7 is fr more object-oriented. In this exmple, doesn t know or cre 7
Mechnic Mechnic bicycles bicycles for ech bicycle clen bicycle(bike) Mechnic for ech bicycle prepre bicycle(bike) pump tires(bike) prepre_trip(self) clen_bicycle(bike) lube chin(bike) bicycles etc... check brkes(bike) Mechnic ls Mechnic how to prepre ech Bicycle. prepre_bicycle(bike) for ech bicycle Mechnic Figure 4.6 A sks Mechnic to prepre ech Bicycle. Mechnic Figure 4.7 to prepre the. A sks Mechnic to prepre the. 8
nd it must lwys hve this object. Figure 4.7 is fr more object-oriented. In this exmple, doesn t know or cre tht it hs Mechnic nd it doesn t hve ny ide wht the Mechnic will do. merely holds onto n object to which it will send prepre_trip; it trusts the receiver of this messge to behve ppropritely. This pttern llows you to dd newly-introduced preprers to without chnging ny of its code. You cn extend without modifying it. 9
If objects were humn nd could describe their own reltionships, in Figure 4.5 would be telling Mechnic: I know wht I wnt nd I know how you do it; in Figure 4.6: I know wht I wnt nd I know wht you do nd in Figure 4.7: I know wht I wnt nd I trust you to do your prt. This blind trust is keystone of object-oriented design. It llows objects to collborte without binding themselves to context nd is necessry in ny ppliction tht expects to grow nd chnge. 10
11
Grce note: In Grce, methods re by defult public, nd fields re by defult confidentil confidentil mens ccessible to the object itself, nd to the objects tht inherit from it. you cn chnge the defults using nnottions, e.g. def extent is public = 200@200 vr prtner is redble := nobody vrs cn be redble or writble s well s fully public methods tht re not in your interfce should be nnotted s confidentil 12
The Lw of Demeter You should send messges only to: n rgument pssed to you your own instnce vribles n object you crete self, super your clss Avoid globl vribles Avoid objects returned from messges sent to others S.Ducsse 13
Correct Messges somemethod: Prmeter self foo. super somemethod: Prmeter. self clss foo. self instvraccessor foo. instvrone foo. Prmeter foo. thing := Thing new. thing foo S.Ducsse 14
In other words Tlk only to your immedite friends Friends of friends re suspect In other words: You cn ply with yourself. this.method() You cn ply with your own toys (but you cn t tke them prt). field.method(), field.getx() You cn ply with toys tht were given to you. rg.method() And you cn ply with toys you ve mde yourself. A = new A();.method() S.Ducsse 15
Hlt! S.Ducsse 16
Do not skip intermediries! S.Ducsse 17
Solution Follow the Lw of Demeter S.Ducsse 18
Trnsformtion Crburetor +fuelvlveopen Engine + crburtor Cr - engine + incresespeed() Step 1 engine.crburetor.fuelvlveopen = true Crburetor +fuelvlveopen Engine - crburtor speedup() Cr - engine + incresespeed() Step 2 crburetor.fuelvlveopen = true engine.speedup() Crburetor - fuelvlveopen + openfuelvlve Engine - crburtor speedup() Cr - engine + incresespeed() fuelvlveopen = true crburetor.openfuelvlve() engine.speedup() S.Ducsse 19
The Drk side of the Lw of Demeter Clss A instvr: mycollection A» do: Block mycollection do: Block A» collect: Block ^ mycollection collect: Block A» select: Block ^ mycollection select: Block A» detect: Block ^ mycollection detect: Block A» isempty ^ mycollection isempty Ech object itself hs to provide complete interfce S.Ducsse 20
About Accessor methods Some schools sy: Access ll instnce vribles using ccessor methods But Be consistent inside clss: do not mix direct ccess nd ccessor use Initilly: think of ccessors s protected methods tht should not be invoked by clients put them in the privte protocol Put ccessors in ccessing protocol only when necessry S.Ducsse 21
Exmple Scheduler» initilize self tsks: OrderedCollection new. Scheduler» tsks ^ tsks But now everybody cn twek the tsks! S.Ducsse 22
Accessors Accessors re good for lzy initiliztion Scheduler» tsks tsks isnil iftrue: [tsks :=...]. ^ tsks But: ccessors methods should be protected by defult, t lest t the beginning S.Ducsse 23
Provide Complete Interfce Worksttion» ccept: Pcket Pcket ddressee = self ddress iftrue:[ ] ifflse: [ ] - It is the responsibility of n object to offer complete interfce tht protects itself from client intrusion. - Shift the responsibility to the Pcket object Pcket» isaddressedto: Node ^ ddressee = Node ddress Worksttion» ccept: Pcket (Pcket isaddressedto: self) iftrue:[ ] ifflse: [ ] S.Ducsse 24