principles of so3ware construc9on: objects, design, and concurrency part 1: designing...
TRANSCRIPT
1 15-214
SchoolofComputerScience
PrinciplesofSo3wareConstruc9on: Objects,Design,andConcurrencyPart1:DesigningclassesBehavioralsubtypingCharlieGarrod MichaelHilton
2 15-214
Administrivia
• Homework1duetonight11:59p.m.– Everyonemustreadandsignourcollabora9onpolicy
• ReadingdueTuesday:Effec9veJava,Items15and39• Homework2duenextThursdayat11:59p.m.
3 15-214
KeyconceptsfromTuesday
4 15-214
KeyconceptsfromTuesday
• Javahasabipar9tetypesystem:primi9vesandobjects• PowerofOOprogrammingcomesfromdynamicdispatch• Introduc9ontotes9ng!
– Testearly,testo3en
5 15-214
Today
• Func9onalcorrectness,con9nued• Behavioralsubtyping
– LiskovSubs9tu9onPrinciple– Thejava.lang.Objectcontracts
6 15-214
Unittes9ng
• Testsforsmallunits:methods,classes,subsystems– Smallesttestablepartofasystem– Testpartsbeforeassemblingthem– Intendedtocatchlocalbugs
• TypicallywriZenbydevelopers• Manysmall,fast-running,independenttests• Fewdependenciesonothersystempartsorenvironment
7 15-214
JUnit
• Apopular,easy-to-use,unit-tes9ngframeworkforJava
8 15-214
AJUnitexample
importorg.junit.Test;importstaticorg.junit.Assert.assertEquals;publicclassAdjacencyListTest{
@TestpublicvoidtestSanityTest(){ Graphg1=newAdjacencyListGraph(10); Vertexs1=newVertex("A"); Vertexs2=newVertex("B"); assertEquals(true,g1.addVertex(s1)); assertEquals(true,g1.addVertex(s2)); assertEquals(true,g1.addEdge(s1,s2)); assertEquals(s2,g1.getNeighbors(s1)[0]);}
@Testpublicvoidtest….
privateinthelperMethod…
}
9 15-214
Selec9ngtestcases
• Writetestsbasedonthespecifica9on,for:– Representa9vecases– Invalidcases– Boundarycondi9ons
• Writestresstests– Automa9callygeneratehugenumbersoftestcases
• ThinklikeanaZacker• Othertests:performance,security,systeminterac9ons,…
10 15-214
Ates9ngexample/***computesthesumofthefirstlenvaluesofthearray**@paramarrayarrayofintegersofatleastlengthlen*@paramlennumberofelementstosumup*@returnsumofthefirstlenarrayvalues*@throwsNullPointerExceptionifarrayisnull*@throwsArrayIndexOutOfBoundsExceptioniflen>array.length*@throwsIllegalArgumentExceptioniflen<0*/intpartialSum(intarray[],intlen);
11 15-214
Ates9ngexample/***computesthesumofthefirstlenvaluesofthearray**@paramarrayarrayofintegersofatleastlengthlen*@paramlennumberofelementstosumup*@returnsumofthefirstlenarrayvalues*@throwsNullPointerExceptionifarrayisnull*@throwsArrayIndexOutOfBoundsExceptioniflen>array.length*@throwsIllegalArgumentExceptioniflen<0*/intpartialSum(intarray[],intlen);
• Testnullarray• Testlength>array.length• Testnega9velength• Testsmallarraysoflength0,1,2• Testlongarray• Testlength==array.length• Stresstestwithrandomly-generatedarraysandlengths
12 15-214
Ates9ngexercise/***Copiesthespecifiedarray,truncatingorpaddingwithzeros*sothecopyhasthespecifiedlength.Forallindicesthatare*validinboththeoriginalarrayandthecopy,thetwoarrayswill*containidenticalvalues.Foranyindicesthatarevalidinthe*copybutnottheoriginal,thecopywillcontain0.*Suchindiceswillexistifandonlyifthespecifiedlength*isgreaterthanthatoftheoriginalarray.**@paramoriginalthearraytobecopied*@paramnewLengththelengthofthecopytobereturned*@returnacopyoftheoriginalarray,truncatedorpaddedwith*zerostoobtainthespecifiedlength*@throwsNegativeArraySizeExceptionifnewLengthisnegative*@throwsNullPointerExceptioniforiginalisnull*/int[]copyOf(int[]original,intnewLength);
13 15-214
Testorganiza9onconven9ons
• HaveatestclassFooTestforeachpublicclassFoo
• Separatesourceandtestdirectories– FooTestandFoointhesamepackage
14 15-214
Testablecode
• Thinkabouttes9ngwhenwri9ngcode– Modularityandtestabilitygohandinhand
• Sametestcanbeusedonallimplementa9onsofaninterface!• Test-drivendevelopment
– Wri9ngtestsbeforeyouwritethecode– TestscanexposeAPIweaknesses
15 15-214
Wri9ngtestablecode//700LOC public boolean foo() { try { synchronized () { if () { } else { } for () { if () { if () { if () { if ()? { if () { for () { } } } } else { if () { for () { if () { } else { } if () { } else { if () { } } if () { if () { if () { for () { } } } } else { } } } else { } } } } }
Source: http://thedailywtf.com/Articles/Coding-Like-the-Tour-de-France.aspx
Unittes9ngasadesignmechanism:• Codewithlowcomplexity• Clearinterfacesand
specifica9ons
16 15-214
Runtestsfrequently
• Runtestsbeforeeverycommit– Donotcommitcodethatfailsatest
• Ifen9retestsuitebecomestoolargeandslow:– Runlocalpackage-leveltests("smoketests“)frequently– Runalltestsnightly– Mediumsizedprojectseasilyhave1000softestcases
• Con9nuousintegra9onserversscaletes9ng
17 15-214
Con9nuousintegra9on:TravisCI
18 15-214
Con9nuousintegra9on:TravisCIbuildhistory
19 15-214
Whenshouldyoustopwri9ngtests?
20 15-214
Whenshouldyoustopwri9ngtests?
• Whenyourunoutofmoney…• Whenyourhomeworkisdue…• Whenyoucan'tthinkofanynewtestcases...• Thecoverageofatestsuite
– Tryingtotestallpartsoftheimplementa9on– Statementcoverage:percentageofprogramstatementsexecuted
• Compareto:methodcoverage,branchcoverage,pathcoverage
21 15-214
Today
• Func9onalcorrectness,con9nued• Behavioralsubtyping
– LiskovSubs9tu9onPrinciple– Thejava.lang.Objectcontracts
22 15-214
Theclasshierarchy
• TherootisObject(allnon-primi9vesareObjects)• AllclassesexceptObjecthaveoneparentclass
– Specifiedwithanextendsclause:classGuitarextendsInstrument{...}
– IfextendsclauseisomiZed,defaultstoObject• Aclassisaninstanceofallitssuperclasses
Object
ToyInstrument
YoyoGuitar
23 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
This is called the Liskov Substitution Principle.
24 15-214
Behavioralsubtyping
• e.g.,Compiler-enforcedrulesinJava:– Subtypescanadd,butnotremovemethods– Concreteclassmustimplementallundefinedmethods– Overridingmethodmustreturnsametypeorsubtype– Overridingmethodmustacceptthesameparametertypes– Overridingmethodmaynotthrowaddi9onalexcep9ons
• Alsoappliestospecifiedbehavior.Subtypesmusthave:– 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.
25 15-214
LSPexample:CarisabehavioralsubtypeofVehicle
abstractclassVehicle{intspeed,limit;//@invariantspeed<limit;//@requiresspeed!=0;//@ensuresspeed<\old(speed)abstractvoidbrake();}
classCarextendsVehicle{intfuel;booleanengineOn;//@invariantspeed<limit;//@invariantfuel>=0;//@requiresfuel>0&&!engineOn;//@ensuresengineOn;voidstart(){…}voidaccelerate(){…}//@requiresspeed!=0;//@ensuresspeed<\old(speed)voidbrake(){…}}
Subclass fulfills the same invariants (and additional ones) Overridden method has the same pre and postconditions
26 15-214
LSPexample:HybridisabehavioralsubtypeofCar
classCarextendsVehicle{intfuel;booleanengineOn;//@invariantspeed<limit;//@invariantfuel>=0;//@requiresfuel>0&&!engineOn;//@ensuresengineOn;voidstart(){…}voidaccelerate(){…}//@requiresspeed!=0;//@ensuresspeed<\old(speed)voidbrake(){…}}
classHybridextendsCar{intcharge;//@invariantcharge>=0;//@invariant…//@requires(charge>0||fuel>0)
&&!engineOn;//@ensuresengineOn;voidstart(){…}voidaccelerate(){…}//@requiresspeed!=0;//@ensuresspeed<\old(speed)//@ensurescharge>\old(charge)voidbrake(){…}}Subclass fulfills the same invariants (and additional ones)
Overridden method start has weaker precondition Overridden method brake has stronger postcondition
27 15-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//methods
}
classSquareextendsRectangle{Square(intw){ super(w,w);}
}
28 15-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//methods
}
classSquareextendsRectangle{Square(intw){ super(w,w);}
}
(Yes.)
29 15-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//methods
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
}
30 15-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//methods
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
}
(Yes.)
31 15-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//@requiresfactor>0;
voidscale(intfactor){ w=w*factor; h=h*factor;}
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
}
32 15-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//@requiresfactor>0;
voidscale(intfactor){ w=w*factor; h=h*factor;}
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
}
(Yes.)
33 15-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//@requiresfactor>0;
voidscale(intfactor){ w=w*factor; h=h*factor;}
//@requiresneww>0;voidsetWidth(intneww){ w=neww;}
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
}
34 15-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//@requiresfactor>0;
voidscale(intfactor){ w=w*factor; h=h*factor;}
//@requiresneww>0;voidsetWidth(intneww){ w=neww;}
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
}
← Invalidates stronger invariant (h==w) in subclass
classGraphicProgram{voidscaleW(Rectangler,intf){r.setWidth(r.getWidth()*f);}}
(Yes! But the Square is not a square…)
35 15-214
ThisSquareisnotabehavioralsubtypeofRectangle
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//@requiresfactor>0;
voidscale(intfactor){ w=w*factor; h=h*factor;}
//@requiresneww>0;//@ensuresw==neww&&h==old.h;
voidsetWidth(intneww){ w=neww;}
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
//@requiresneww>0;//@ensuresw==neww&&h==neww;@OverridevoidsetWidth(intneww){w=neww;h=neww;}}
36 15-214
Today
• Func9onalcorrectness,con9nued• Behavioralsubtyping
– LiskovSubs9tu9onPrinciple– Thejava.lang.Objectcontracts
37 15-214
MethodscommontoallObjects
• equals:returnstrueifthetwoobjectsare“equal”• hashCode:returnsanintthatmustbeequalforequalobjects,
andislikelytodifferforunequalobjects• toString:returnsaprintablestringrepresenta9on
38 15-214
Thebuilt-injava.lang.Objectimplementa9ons
• Provideiden9tyseman9cs:– equals(Objecto):returnstrueiforeferstothisobject– hashCode():returnsanear-randomintthatneverchanges– toString():returnsastringconsis9ngofthetypeandhashcode
• Forexample:java.lang.Object@659e0bfd
39 15-214
ThetoString()specifica9on
• Returnsaconcise,butinforma9vetextualrepresenta9on• Advice:AlwaysoverridetoString(),e.g.:
finalclassPhoneNumber{privatefinalshortareaCode;privatefinalshortprefix;privatefinalshortlineNumber;...@OverridepublicStringtoString(){returnString.format("(%03d)%03d-%04d",areaCode,prefix,lineNumber);}}Numberjenny=...;System.out.println(jenny);Prints:(707)867-5309
40 15-214
Theequals(Object)specifica9on
• Mustdefineanequivalencerela9on:– Reflexive:Foreveryobjectx,x.equals(x)isalwaystrue– Symmetric:Ifx.equals(y),theny.equals(x)– Transi9ve:Ifx.equals(y)andy.equals(z),thenx.equals(z)
• Consistent:Equalobjectsstayequal,unlessmutated• "Non-null":x.equals(null)isalwaysfalse
41 15-214
Anequals(Object)example
publicfinalclassPhoneNumber{privatefinalshortareaCode;privatefinalshortprefix;privatefinalshortlineNumber;@Overridepublicbooleanequals(Objecto){if(!(oinstanceofPhoneNumber))//Doesnullcheckreturnfalse;PhoneNumberpn=(PhoneNumber)o;returnpn.lineNumber==lineNumber&&pn.prefix==prefix&&pn.areaCode==areaCode;}...}
42 15-214
ThehashCode()specifica9on
• Equalobjectsmusthaveequalhashcodes– IfyouoverrideequalsyoumustoverridehashCode
• Unequalobjectsshouldusuallyhavedifferenthashcodes– Takeallvaluefieldsintoaccountwhenconstruc9ngit
• Hashcodemustnotchangeunlessobjectismutated
43 15-214
AhashCode()example
publicfinalclassPhoneNumber{privatefinalshortareaCode;privatefinalshortprefix;privatefinalshortlineNumber;@OverridepublicinthashCode(){intresult=17;//Nonzeroisgoodresult=31*result+areaCode;//Constantmustbeoddresult=31*result+prefix;//""""result=31*result+lineNumber;//""""returnresult;}...}
44 15-214
Summary
• Pleasecompletethecoursereadingassignments• Testearly,testo3en!• Subtypesmustfulfillbehavioralcontracts• AlwaysoverridehashCodeifyouoverrideequals• Alwaysuse@Overrideifyouintendtooverrideamethod
– OrletyourIDEgeneratethesemethodsforyou…