josh bloch charlie garrodcharlie/courses/15-214/2016-fall/slides/... · 2016-09-13 · 1. (compile...
TRANSCRIPT
1 15-214
SchoolofComputerScience
PrinciplesofSo3wareConstruc9on: Objects,Design,andConcurrencyDesigningclassesDelega9onandinheritanceandbehavioralsubtyping(ohmy)JoshBloch CharlieGarrod
2 15-214
Administrivia
• Homework2dueThursday
3 15-214
KeyconceptsfromThursday…
4 15-214
Whatisacontract?
• Agreementbetweenanobjectanditsuser• Includes
– Methodsignature(typespecifica9ons)– Func9onalityandcorrectnessexpecta9ons– Performanceexpecta9ons
• Whatthemethoddoes,nothowitdoesit– Interface(API),notimplementa9on
• “Focusonconceptsratherthanopera9ons”
5 15-214
The==operatorvs.equalsmethod
• Forprimi9vesyoumustuse==• Forobjectreferencetypes
– The==operatorprovidesiden*tyseman*cs• ExactlyasimplementedbyObject.equals• EvenifObject.equalshasbeenoverridden• Thisisseldomwhatyouwant!
– youshould(almost)alwaysuse.equals– Using==onanobjectreferenceisabadsmellincodeif(input=="yes")//Abug!!!
6 15-214
TheequalscontractinEnglish
• Reflexive–everyobjectisequaltoitself• Symmetric–ifa.equals(b)thenb.equals(a)• TransiCve–ifa.equals(b)andb.equals(c),thena.equals(c)
• Consistent–equalobjectsstayequalunlessmutated• “Non-null”–a.equals(null)returnsfalse• Takentogethertheseensurethatequalsisaglobalequivalence
relaConoverallobjects
7 15-214
Learninggoalsfortoday
• Beabletoexplaininheritanceanddelega9on• Applyinheritanceanddelega9onappropriatelyforreuse
– Understandtheirtradeoffs• Behavioralsubtypingandimplica9onsforspecifica9onandtes9ng
8 15-214
Today:Class-levelreusewithdelega9onandinheritance
• Delega9on• Inheritance
– Java-specificdetailsforinheritance• Behavioralsubtyping:Liskov'sSubs9tu9onPrinciple• Thursday:Designpabernsforimprovedclass-levelreuse• Laterinthecourse:
– System-levelreusewithlibrariesandframeworks
9 15-214
Thepromiseofreuse:
# Products
Cost With reuse
Without reuse
10 15-214
COMPOSITIONANDDELEGATION
11 15-214
Recallourearliersor9ngexample:
staticvoidsort(int[]list,booleanascending){…booleanmustSwap;if(ascending){mustSwap=list[i]<list[j];}else{mustSwap=list[i]>list[j];}…}
interfaceComparator{booleancompare(inti,intj);}finalComparatorASCENDING=(i,j)->i<j;finalComparatorDESCENDING=(i,j)->i>j;staticvoidsort(int[]list,Comparatorcmp){…booleanmustSwap=cmp.compare(list[i],list[j]);…}
Version A:
Version B':
12 15-214
Delega9on
• Delega*onissimplywhenoneobjectreliesonanotherobjectforsomesubsetofitsfunc9onality– e.g.here,theSorterisdelega9ngfunc9onalitytosomeComparator
• Judiciousdelega9onenablescodereuse
interfaceComparator{booleancompare(inti,intj);}finalComparatorASCENDING=(i,j)->i<j;finalComparatorDESCENDING=(i,j)->i>j;staticvoidsort(int[]list,Comparatorcmp){…booleanmustSwap=cmp.compare(list[i],list[j]);…}
13 15-214
Delega9on
• Delega*onissimplywhenoneobjectreliesonanotherobjectforsomesubsetofitsfunc9onality– e.g.here,theSorterisdelega9ngfunc9onalitytosomeComparator
• Judiciousdelega9onenablescodereuse– Sortercanbereusedwitharbitrarysortorders– Comparatorscanbereusedwitharbitraryclientcodethatneedsto
compareintegers
14 15-214
Usingdelega9ontoextendfunc9onality
• Considerthejava.util.List(excerpted):publicinterfaceList<E>{publicbooleanadd(Ee);publicEremove(intindex);publicvoidclear();…}
• Supposewewantalistthatlogsitsopera9onstotheconsole…
15 15-214
Usingdelega9ontoextendfunc9onality
• Onesolu9on:publicclassLoggingList<E>implementsList<E>{privatefinalList<E>list;publicLoggingList<E>(List<E>list){this.list=list;}publicbooleanadd(Ee){System.out.println("Adding"+e);returnlist.add(e);}publicEremove(intindex){System.out.println("Removingat"+index);returnlist.remove(index);}…
TheLoggingListiscomposedofaList,anddelegates(thenon-logging)func9onalitytothatList
16 15-214
Delega9onanddesign
• Smallinterfaceswithclearcontracts• Classestoencapsulatealgorithms,behaviors
– E.g.,theComparator
17 15-214
IMPLEMENTATIONINHERITANCEANDABSTRACTCLASSES
18 15-214
Varia9onintherealworld:typesofbankaccounts
publicinterfaceCheckingAccount{publiclonggetBalance();publicvoiddeposit(longamount);publicbooleanwithdraw(longamount);publicbooleantransfer(longamount,Account???target);publiclonggetFee();}
publicinterfaceSavingsAccount{publiclonggetBalance();publicvoiddeposit(longamount);publicbooleanwithdraw(longamount);publicbooleantransfer(longamount,Account???target);publicdoublegetInterestRate();}
19 15-214
Interfaceinheritanceforanaccounttypehierarchy
publicinterfaceAccount{publiclonggetBalance();publicvoiddeposit(longamount);publicbooleanwithdraw(longamount);publicbooleantransfer(longamount,Accounttarget);publicvoidmonthlyAdjustment();}
publicinterfaceCheckingAccountextendsAccount{publiclonggetFee();}
publicinterfaceSavingsAccountextendsAccount{publicdoublegetInterestRate();}
publicinterfaceInterestCheckingAccountextendsCheckingAccount,SavingsAccount{}
20 15-214
Thepowerofobject-orientedinterfaces
• Subtypepolymorphism– Differentkindsofobjectscanbetreateduniformlybyclientcode– Eachobjectbehavesaccordingtoitstype
• e.g.,ifyouaddnewkindofaccount,clientcodedoesnotchange: Iftodayisthelastdayofthemonth:
ForeachacctinallAccounts:acct.monthlyAdjustment();
21 15-214
publicabstractclassAbstractAccount implementsAccount{protectedlongbalance=0;publiclonggetBalance(){ returnbalance;}abstractpublicvoidmonthlyAdjustment();//othermethods…
}publicclassCheckingAccountImpl extendsAbstractAccount implementsCheckingAccount{publicvoidmonthlyAdjustment(){ balance-=getFee();}publiclonggetFee(){…}
}
Implementa9oninheritanceforcodereuse
22 15-214
publicabstractclassAbstractAccount implementsAccount{protectedlongbalance=0;publiclonggetBalance(){ returnbalance;}abstractpublicvoidmonthlyAdjustment();//othermethods…
}publicclassCheckingAccountImpl extendsAbstractAccount implementsCheckingAccount{publicvoidmonthlyAdjustment(){ balance-=getFee();}publiclonggetFee(){…}
}
Implementa9oninheritanceforcodereuse
protectedelementsarevisibleinsubclasses
anabstractclassismissingtheimplementa9onofone
ormoremethods
anabstractmethodisle3tobe
implementedinasubclass
noneedtodefinegetBalance()–thecodeisinheritedfrom
AbstractAccount
23 15-214
Inheritance:aglimpseatthehierarchy
• ExamplesfromJava– java.lang.Object– Collec9onslibrary
24 15-214
JavaCollec9onsAPI(excerpt)
Collection
List Set AbstractCollection
AbstractList
LinkedList
Vector
HashSet
AbstractSequentialList
AbstractSet
Cloneable
ArrayList
interfaces
25 15-214
Benefitsofinheritance
• Reuseofcode• Modelingflexibility• AJavaaside:
– Eachclasscandirectlyextendonlyoneparentclass– Aclasscanimplementmul9pleinterfaces
26 15-214
Inheritanceandsubtyping
• Inheritanceisforcodereuse– Writecodeonceandonlyonce– Superclassfeaturesimplicitlyavailablein
subclass
• Subtypingisforpolymorphism– Accessingobjectsthesameway,butgefng
differentbehavior– Subtypeissubs9tutableforsupertype
classAextendsB
classAimplementsIclassAextendsB
27 15-214
Typicalrolesforinterfacesandclasses
• Aninterfacedefinesexpecta9ons/commitmentsforclients• Aclassfulfillstheexpecta9onsofaninterface
– Anabstractclassisaconvenienthybrid– Asubclassspecializesaclass'simplementa9on
28 15-214
Javadetails:extendedreusewithsuper
publicabstractclassAbstractAccountimplementsAccount{protectedlongbalance=0;publicbooleanwithdraw(longamount){//withdrawsmoneyfromaccount(codenotshown)}
}publicclassExpensiveCheckingAccountImpl extendsAbstractAccountimplementsCheckingAccount{publicbooleanwithdraw(longamount){ balance-=HUGE_ATM_FEE; booleansuccess=super.withdraw(amount) if(!success) balance+=HUGE_ATM_FEE; returnsuccess;}
}
Overrideswithdrawbutalsousesthesuperclasswithdrawmethod
29 15-214
Javadetails:constructorswiththisandsuper
publicclassCheckingAccountImpl extendsAbstractAccountimplementsCheckingAccount{
privatelongfee;
publicCheckingAccountImpl(longinitialBalance,longfee){ super(initialBalance); this.fee=fee;}
publicCheckingAccountImpl(longinitialBalance){ this(initialBalance,500);}/*othermethods…*/} Invokesanother
constructorinthissameclass
Invokesaconstructorofthesuperclass.Mustbethe
firststatementoftheconstructor.
30 15-214
Javadetails:final
• Afinalfield:preventsreassignmenttothefielda3erini9aliza9on• Afinalmethod:preventsoverridingthemethod• Afinalclass:preventsextendingtheclass
– e.g.,publicfinalclassCheckingAccountImpl{…
31 15-214
Note:type-cas9nginJava
• Some9mesyouwantadifferenttypethanyouhave– e.g., doublepi=3.14; intindianaPi=(int)pi;
• Usefulifyouknowyouhaveamorespecificsubtype:– e.g., Accountacct=…;CheckingAccountcheckingAcct=(CheckingAccount)acct;longfee=checkingAcct.getFee();– WillgetaClassCastExceptioniftypesareincompa9ble
• Advice:avoiddowncas9ngtypes– Never(?)downcastwithinsuperclasstoasubclass
32 15-214
Note:instanceof
• OperatorthattestswhetheranobjectisofagivenclasspublicvoiddoSomething(Accountacct){longadj=0;if(acctinstanceofCheckingAccount){checkingAcct=(CheckingAccount)acct;adj=checkingAcct.getFee();
}elseif(acctinstanceofSavingsAccount){savingsAcct=(SavingsAccount)acct;adj=savingsAcct.getInterest();
}…}
• Advice:avoidinstanceofifpossible– Never(?)useinstanceofinasuperclasstochecktypeagainstsubclass
Warning: This code is bad.
33 15-214
Javadetails:Dynamicmethoddispatch
1. (Compile9me)Determinewhichclasstolookin2. (Compile9me)Determinemethodsignaturetobeexecuted
1. Findallaccessible,applicablemethods2. Selectmostspecificmatchingmethod
34 15-214
Javadetails:Dynamicmethoddispatch
1. (Compile9me)Determinewhichclasstolookin2. (Compile9me)Determinemethodsignaturetobeexecuted
1. Findallaccessible,applicablemethods2. Selectmostspecificmatchingmethod
3. (Run9me)Determinedynamicclassofthereceiver4. (Run9me)Fromdynamicclass,locatemethodtoinvoke
1. Lookformethodwiththesamesignaturefoundinstep22. Otherwisesearchinsuperclassandetc.
35 15-214
Designwithinheritance(ornot)
• Favorcomposi9onoverinheritance– Inheritanceviolatesinforma9onhiding
• Designanddocumentforinheritance,orprohibitit– Documentrequirementsforoverridinganymethod
36 15-214
BEHAVIORALSUBTYPING
37 15-214
Behavioralsubtyping
• e.g.,Compiler-enforcedrulesinJava:– Subtypescanadd,butnotremovemethods– Concreteclassmustimplementallundefinedmethods– Overridingmethodmustreturnsametypeorsubtype– Overridingmethodmustacceptthesameparametertypes– Overridingmethodmaynotthrowaddi9onalexcep9ons
Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.
Barbara Liskov
38 15-214
Behavioralsubtyping
• e.g.,Compiler-enforcedrulesinJava:– Subtypescanadd,butnotremovemethods– Concreteclassmustimplementallundefinedmethods– Overridingmethodmustreturnsametypeorsubtype– Overridingmethodmustacceptthesameparametertypes– Overridingmethodmaynotthrowaddi9onalexcep9ons
• Alsoappliestospecifiedbehavior:– Sameorstrongerinvariants– Sameorstrongerpostcondi9onsforallmethods– Sameorweakerprecondi9onsforallmethods
Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.
Barbara Liskov
This is called the Liskov Substitution Principle.
39 15-214
abstract class Vehicle { int speed, limit;
//@ invariant speed < limit;
//@ requires speed != 0; //@ ensures speed < \old(speed) void brake();
}
class Car extends Vehicle { int fuel; boolean engineOn; //@ invariant speed < limit; //@ invariant fuel >= 0;
//@ requires fuel > 0 && !engineOn; //@ ensures engineOn; void start() { … }
void accelerate() { … }
//@ requires speed != 0; //@ ensures speed < \old(speed) void brake() { … }
}
Subclass fulfills the same invariants (and additional ones) Overridden method has the same pre and postconditions
Behavioralsubtyping(LiskovSubs9tu9onPrinciple)
40 15-214
class Car extends Vehicle { int fuel; boolean engineOn; //@ invariant fuel >= 0;
//@ requires fuel > 0 && !engineOn; //@ ensures engineOn; void start() { … }
void accelerate() { … }
//@ requires speed != 0; //@ ensures speed < old(speed) void brake() { … }
}
class Hybrid extends Car { int charge; //@ invariant charge >= 0;
//@ requires (charge > 0 || fuel > 0) && !engineOn; //@ ensures engineOn; void start() { … }
void accelerate() { … }
//@ requires speed != 0; //@ ensures speed < \old(speed) //@ ensures charge > \old(charge) void brake() { … }
}
Subclass fulfills the same invariants (and additional ones) Overridden method start has weaker precondition Overridden method brake has stronger postcondition
Behavioralsubtyping(LiskovSubs9tu9onPrinciple)
41 15-214
class Rectangle { int h, w; Rectangle(int h, int w) { this.h=h; this.w=w; }
//methods
}
class Square extends Rectangle { Square(int w) { super(w, w); }
}
Is this Square a behavioral subtype of Rectangle?
Behavioralsubtyping(LiskovSubs9tu9onPrinciple)
42 15-214
class Rectangle { int h, w; Rectangle(int h, int w) { this.h=h; this.w=w; }
//methods
}
class Square extends Rectangle { Square(int w) { super(w, w); }
}
Is this Square a behavioral subtype of Rectangle? (Yes.)
Behavioralsubtyping(LiskovSubs9tu9onPrinciple)
43 15-214
class Rectangle { //@ invariant h>0 && w>0; int h, w; Rectangle(int h, int w) { this.h=h; this.w=w; }
//methods
}
class Square extends Rectangle { //@ invariant h>0 && w>0;
//@ invariant h==w; Square(int w) { super(w, w); }
}
Behavioralsubtyping(LiskovSubs9tu9onPrinciple)
Is this Square a behavioral subtype of Rectangle?
44 15-214
class Rectangle { //@ invariant h>0 && w>0; int h, w; Rectangle(int h, int w) { this.h=h; this.w=w; }
//methods
}
class Square extends Rectangle { //@ invariant h>0 && w>0;
//@ invariant h==w; Square(int w) { super(w, w); }
}
Behavioralsubtyping(LiskovSubs9tu9onPrinciple)
Is this Square a behavioral subtype of Rectangle? (Yes.)
45 15-214
class Rectangle { //@ invariant h>0 && w>0; int h, w; Rectangle(int h, int w) { this.h=h; this.w=w; }
//@ requires factor > 0;
void scale(int factor) { w=w*factor; h=h*factor; }
}
class Square extends Rectangle { //@ invariant h>0 && w>0; //@ invariant h==w; Square(int w) { super(w, w); }
}
Is this Square a behavioral subtype of Rectangle?
Behavioralsubtyping(LiskovSubs9tu9onPrinciple)
46 15-214
class Rectangle { //@ invariant h>0 && w>0; int h, w; Rectangle(int h, int w) { this.h=h; this.w=w; }
//@ requires factor > 0;
void scale(int factor) { w=w*factor; h=h*factor; }
}
class Square extends Rectangle { //@ invariant h>0 && w>0; //@ invariant h==w; Square(int w) { super(w, w); }
}
Is this Square a behavioral subtype of Rectangle? (Yes.)
Behavioralsubtyping(LiskovSubs9tu9onPrinciple)
47 15-214
class Rectangle { //@ invariant h>0 && w>0; int h, w; Rectangle(int h, int w) { this.h=h; this.w=w; }
//@ requires factor > 0; void scale(int factor) { w=w*factor; h=h*factor; } //@ requires neww > 0; void setWidth(int neww) { w=neww; }
}
class Square extends Rectangle { //@ invariant h>0 && w>0; //@ invariant h==w; Square(int w) { super(w, w); }
}
Behavioralsubtyping(LiskovSubs9tu9onPrinciple)
Is this Square a behavioral subtype of Rectangle?
48 15-214
class Rectangle { //@ invariant h>0 && w>0; int h, w; Rectangle(int h, int w) { this.h=h; this.w=w; }
void scale(int factor) { w=w*factor; h=h*factor; }
void setWidth(int neww) { w=neww; }
}
class Square extends Rectangle { //@ invariant h>0 && w>0; //@ invariant h==w; Square(int w) { super(w, w); }
}
Yes? (But the Square is not actually a square…)
← Invalidates stronger invariant (w==h) in subclass
classGraphicProgram{voidscaleW(Rectangler,intfactor){r.setWidth(r.getWidth()*factor);}}
Behavioralsubtyping(LiskovSubs9tu9onPrinciple)
49 15-214
Summary:Designingreusableclasses
• Reusableimplementa9onswithsimple,clearcontracts• Inheritanceforreuse,itspipalls,anditsalterna9ves• Liskov'sSubs9tu9onPrincipleforbehavioralsubtyping