301aa - advanced programming [ap-2017] -...
TRANSCRIPT
301AA-AdvancedProgramming[AP-2017]
Lecturer:[email protected]:[email protected]
DepartmentofComputerScience,PisaAcademicYear2017/18
AP-2017-11:FrameworksandInversionofControl
FrameworksandInversionofControl
• Recap:JavaBeansasComponents• Frameworks,ComponentFrameworksandtheirfeatures
• FrameworksvsIDEs• InversionofControlandContainers• FrameworksvsLibraries• DecouplingComponents• DependencyInjecVon• IoCContainersinSpring
2
Components:arecap
• Example:JavaBeans• Contractuallyspecifiedinterfaces:events,methodsandproperVes
• Explicitcontextdependencies:serializable,constructorwithnoargument
• Subjecttocomposi?on:connecVontootherbeans– UsingconnecVonorientedprogramming(eventsourceandlisteners)
3
Aso$warecomponentisaunitofcomposi1onwithcontractuallyspecifiedinterfacesandexplicitcontextdependenciesonly.Aso\warecomponentcanbedeployedindependentlyandissubjecttocomposi1onbythirdparty.ClemensSzyperski,ECOOP1996
TowardsComponentFrameworks• So$wareFramework:AcollecVonofcommoncodeproviding
genericfunc?onalitythatcanbeselec?velyoverriddenorspecializedbyusercodeprovidingspecificfunc?onality
• Applica1onFramework:Aso\wareframeworkusedtoimplementthestandardstructureofanapplicaVonforaspecificdevelopmentenvironment
• Web(Applica1on)Framework:asabove,forWebApplicaVons– ASP.NETbyMicroso\forwebsites,webapplicaVonsandweb
services– GWT-GoogleWebToolkit(GWT)– Rails-WriBeninRuby-Providesdefaultstructuresfordatabases,
webservicesandwebpages.– Spring- forJava-basedenterprisewebapplicaVons
4
ExamplesofFrameworks
• Generalso\wareframeworks– .NET–Windowsplaborm.Provideslanguageinteroperability
– AndroidSDK–SupportsdevelopmentofappsinJava(butdoesnotuseaJVM!)
– Cocoa–Apple’snaVveOOAPIformacOS.IncludesCstandardlibraryandtheObjecVve-CrunVme.
– Eclipse–Cross-plaborm,easilyextensibleIDEwithplugins
ExamplesofFrameworks
• FrameworksforApplicaVonwithGUI– MFC-Microso\FoundaVonClassLibrary.C++object-orientedlibraryforWindows.
– Gnome–WriBeninC;mainlyforLinux
– Qt-Cross-plaborm;wriBeninC++
ExamplesofFrameworks
• WebApplicaVonFrameworks[basedonModel-View-ControllerdesignpaBern]– ASP.NETbyMicroso\forwebsites,webapplicaVonsandwebservices
– GWT-GoogleWebToolkit(GWT)– Rails-WriBeninRuby-Providesdefaultstructuresfordatabases,webservicesandwebpages.
ExamplesofFrameworks
• Concurrency– HadoopMap/Reduce-so\wareframeworkforapplicaVonswhichprocessbigamountsofdatain-parallelonlargeclusters(thousandsofnodes)inafault-tolerantmanner.
• Map:Takesinputdataandconvertsitintoasetoftuples(key/valuepairs).
• Reduce:TakestheoutputfromMapandcombinesthedatatuplesintoasmallersetoftuples.
FeaturesofFrameworks• Aframeworkembodiessomeabstractdesign,withmorebehaviorbuiltin.
• Inordertouseityouneedtoinsertyourbehaviorintovariousplacesintheframeworkeitherbysubclassingorbyplugginginyourownclasses.
• Theframework’scodethencallsyourcodeatthesepoints.
• Averygeneralconcept,emphasizinginversionofcontrol:asopposedtolibrariesisthecodeoftheframeworkthatcallsthecode
10
ComponentFrameworks• Frameworksthatsupportdevelopment,deployment,composiVon
andexecuVonofcomponentsdesignedaccordingtoagivenComponentModel
• Supportthedevelopmentofindividualcomponents,enforcingthedesignofpreciseinterfaces
• Supportthecomposi1on/connec1onofcomponentsaccordingtothemechanismsprovidedbytheComponentModel
• Allowsinstancesofthesecomponentstobe“plugged”intothecomponentframeworkitself
• Provideprebuiltfunc1onali1es,suchasusefulcomponentsorautomatedassemblyfuncVonsthatautomaVcallyinstanVateandcomposecomponentstoperformcommontasks.
• ThecomponentframeworkestablishesenvironmentalcondiVonsforthecomponentinstancesandregulatestheinteracVonbetweencomponentinstances.
11
FrameworksvsIDEs
• Orthogonalconcepts• AframeworkcanbesupportedbyseveralIDEs
– Eg:SpringsupportedbySpringToolSuite(basedonEclipse),NetBeans,IntelliJIDEA,Eclipse,…
• AnIDEcansupportseveralframeworks– Eg:NetBeanssupportsJavaBeans,Spring,J2EE,Maven,Hibernate,JavaServerFaces,Struts,Qt,…
• InteresVngissue:composiVonalapproachtoframeworks
12
FrameworksFeatures• Consistofpartsthatarefoundinmanyappsofthattype
– LibrarieswithAPIs(classeswithmethodsetc.)– Ready-madeextensibleprograms("engines")– SomeVmesalsotools(e.g.fordevelopment,configuraVon,content)
• Frameworks,likeso\warelibraries,providereusableabstrac9onsofcodewrappedinawell-definedAPI
• But:Inversionofcontrol– unlikeinlibraries,theoverallprogram'sflowofcontrolisnotdictated
bythecaller,butbytheframework • Helpssolvingrecurringdesignproblems
– Providingadefaultbehavior– DictaVnghowtofill-in-the-blanks
• Non-modifiableframeworkcode– Extensibility:usuallybyselecVveoverriding
13
Extensibility• Allframeworkscanbeextendedtocaterforapp-specificfuncVonality.– AframeworkisintendedtobeextendedtomeettheneedsofaparVcularapplicaVon
• Commonwaystoextendaframework:– Extensioniscarriedoutbysub-classing,overridingmethods,andimplemenVnginterfaces
– Plug-ins:frameworkcanloadcertainextracodeinaspecificformat
– Withintheframeworklanguage:• Subclassing&overridingmethods• ImplemenVnginterfaces• Registeringeventhandlers
14
Twoselectedtopics
Wegiveacloserlooktotwogeneraltopicsrelatedtoframeworks:• Inversionofcontrol• Masteringdependenciesamongcomponents
15
InversionofControl(IoC)inGUIs
• Intext-basedinteracVon,theorderofinteracVonsandofinvocaVonsisdecidedbythethecode.
• IntheGUI-basedinteracVon,theGUIloopdecideswhentoinvokethemethods,basedontheorderofevents
• AlsoknownastheHollywoodPrinciple–“Don'tcallus,we'llcallyou”.
16
#rubyputs'Whatisyourname?'name=getsprocess_name(name)puts'Whatisyourquest?'quest=getsprocess_quest(quest) TEXT
require'tk'root=TkRoot.new()name_label=TkLabel.new(){text"WhatisYourName?"}name_label.packname=TkEntry.new(root).packname.bind("FocusOut"){process_name(name)}quest_label=TkLabel.new(){text"WhatisYourQuest?"}quest_label.packquest=TkEntry.new(root).packquest.bind("FocusOut"){process_quest(quest)}Tk.mainloop() GUI
https://martinfowler.com/bliki/InversionOfControl.html!
InversionofControlinFrameworks
• WithFrameworkstheInversionofControlbecomesdominant
• TheapplicaVonarchitectureiso\enfixed,evenifcustomizable,anddeterminedbytheFramework– Whenusingaframework,oneusuallyjustimplementsafewcallbackfuncVonsorspecializesafewclasses,andtheninvokesasinglemethodorprocedure.
– Theframeworkdoestherestoftheworkforyou,invokinganynecessaryclientcallbacksormethodsattheappropriateVmeandplace.
• Example:Java'sSwingandAWTclasses,NetBeansprojects– Theyhaveahugeamountofcodetomanagetheuserinterface,andthereisinversionofcontrolbecauseyoustarttheGUIframeworkandthenwaitforittocallyourlisteners
17
InversionofControlTradiVonalProgramExecuVon InversionofControl
TheapphascontrolovertheexecuVonflow,callinglibrarycodewhenitneedsto.
TheframeworkhascontrolovertheexecuVonflow,callingappcodeforapp-specificbehavior.
18
FrameworksvsLibraries• Frameworksconsistoflargesetsofclasses/interfaces,suitablypackaged
• Notmuchdifferentfromlibraries• (Possible)Keyfeature:wideuseofInversionofControl
• “Framework”someVmesintendedas“well-designedlibrary”
• “JavaCollecVonFramework”vs“StandardTemplateLibrary”:arethemframeworksorlibraries?
19
Components,ContainersandIoC• O\enFrameworksprovidecontainersfordeployingcomponents
• AcontainermayprovideatrunVmefuncVonaliVesneededbythecomponentstoexecute
• Example:EJBcontainersareresponsibleofthepersistentstorageofdataandoftheavailabilityofEJB’sforallauthorizedclients
• UsingIoC,EJBcontainerscaninvokeonsessionbeansmethodslikeejbRemove,ejbPassivate(storetosecondarystorage),andejbAc?vate(restorefrompassivestate).
• Spring’sIoCcontainers:arelatedconcept…
21
Looselycoupledsystems:advantagesandtechniques
• GoodOOSystemsshouldbeorganisedaswebofinteracVngobjects
• Goal:Highcohesion,lowcoupling• Advantagesoflowcoupling
– Extensibility– Testability– Reusability
• WediscussDependencyinjec9onandothertechniquestoachieveit
22NickHines-DependencyInjec?onandInversionofControl-ThoughtWorks,2006
TradeMonitor–Thedesign
• TradeMonitoriscoupledtoLimitDao[DataAccessObject]–thisisnotgood!– Extensibility–whatifwereplacethedatabasewithadistributedcache?– Testability–wheredothelimitsfortestcomefrom?– Reusability–logicisfairlygeneric...
public class TradeMonitor { private LimitDao limitDao; public TradeMonitor() { limitDao = new LimitDao(); } public bool TryTrade(string symbol, int amount) { int limit = limitDao.GetLimit(symbol); int exposure = limitDao.GetExposure(symbol); return (exposure + amount > limit) ? false : true; } }
public class LimitDao { public int GetExposure(string symbol) { // Do something with the database } public int GetLimit(string sysmbol) { // Do something with the database } }
limitDao = new LimitDao();
24
TradeMonitor–TheDesignRefactored(1)
• Introduceinterface/implementaVonseparaVon– LogicdoesnotdependonDAOanymore.– Doesthisreallysolvetheproblem?
public class TradeMonitor { private ILimitRepository limitRepository; public TradeMonitor() { limitRepository = new LimitDao(); } public bool TryTrade(string symbol, int amount) {
. . . } }
public interface ILimitRepository { int GetExposure(string symbol); int GetLimit(string symbol); }
limitRepository = new LimitDao();
• TheconstructorsVllhasastaVcdependencyonDAO
25
• IntroduceaFactory.Ithastheresponsibilitytocreatetherequiredinstance.
• TradeMonitordecoupledfromLimitDao• LimitDaosVllVghtly-coupledalbeittoFactory
public class LimitFactory { public static ILimitRepository GetLimitRepository() { return new LimitDao(); } } public class TradeMonitor { private ILimitRepository limitRepository; public TradeMonitor() { limitRepository = LimitFactory.GetLimitRepository(); } public bool TryTrade(string symbol, int amount) { . . . } }
LimitFactory
TradeMonitor
<<interface>>LimitRepository
LimitDao
<<creates>>
return new LimitDao();
26
TradeMonitor–TheDesignRefactored(2)
• IntroduceaServiceLocator.Thisobjectactsasa(staVc)registryfortheLimitDaoyouneed.
• Thisgivesusextensibility,testability,reusabilitypublic class ServiceLocator{ public static void RegisterService(Type type, object impl) {. . .} public static object GetService(Type type) {. . .} } public class TradeMonitor{ private ILimitRepository limitRepository; public TradeMonitor(){ object o = ServiceLocator.GetService(typeof(ILimitRepository)); limitRepository = o as ILimitRepository; } public bool TryTrade(string symbol, int amount){ . . . } }
27
TradeMonitor–TheDesignRefactored(3)
ServiceLocator–Prosandcons
• TheServiceLocatorpaBernsucceedsindecouplingtheTradeMonitorfromtheLimitDao
• Itcanbegeneralizedinseveralways,eg.tocoverdynamiclookup
• Cons:– Aformofsequencedependenceremains– Cumbersomesetupintests– Servicedependsoninfrastructurecode(theServiceLocator)
– Codeneedstohandlelookupproblems
28
TowardsDependencyInjecVon• IntheoriginalsituaVon,weaimat
relaxingthecouplingusingsoluVonsbasedonInversionofControl
Q: Which“control”isinverted?A: ThelookupoftheLimitRepositoryinstancefromTradeMonitor
ThepluginiscreatedbyanexternalAssembleranditispassedtoTradeMonitorinsomeway.Thedependencyisinjectedinthemaincomponent.
29
DependencyInjecVon• Dependencyinjec1onallowsavoidinghard-codeddependencies(strongcoupling)andchangingthem
• AllowsselecVonamongmulVpleimplementaVonsofagivendependencyinterfaceatrunVme
• Examples:– loadpluginsdynamically– replacemockobjectsintestenvironmentsvs.realobjectsinproducVonenvironments
• Threeforms:– SeBerinjecVon– ConstructorinjecVon– (Interfaceinjec?on)
30
DependencyinjecVonbasedonseBermethods
• WhataboutaddingaseZerandletsomethingelseworryaboutcreaVonandresoluVon?
public class TradeMonitor { private ILimitRepository limitRepository; public TradeMonitor() { } public ILimitRepository Limits { set { limitRepository = value;} } public bool TryTrade(string symbol, int amount){ . . . } }
• Thedependenciesareinjectedfromtheoutside
• ComponentsarepassiveandarenotconcernedwithlocaVngorcreaVngdependencies
ThisisSeJerInjec9on
• WidelyusedinSpring
31
DependencyInjecVonbasedonConstructors
• Whynotjustusetheconstructor?
public class TradeMonitor { private ILimitRepository limitRepository; public TradeMonitor(ILimitRepository limitRepository) { this.limitRepository = limitRepository; } public bool TryTrade(string symbol, int amount){ . . . } }
• NoseBersfordependentcomponents,(obviously)
• One-shotiniValisaVon–componentsarealwaysiniValisedcorrectly
• Alldependenciesareclearlyvisiblefromcode
• Itisimpossibletocreatecyclicdependencies
ThisisConstructorInjec9on
• WidelyusedinPicoContainer
32
SoluVonbasedonConstructorInjecVon&TestCase
[TestFixture] public class TradeMonitorTest { [Test] public void MonitorBlocksTradesWhenLimitExceeded() { DynamicMock mockRepository = new DynamicMock(typeof(ILimitRepository)); mockRepository.SetupResult('GetLimit', 1000000, new Type[] { typeof(string) }); mockRepository.SetupResult('GetExposure', 999999, new Type[] { typeof(string) }); TradeMonitor monitor = new TradeMonitor((ILimitRepository)mockRepository.MockInstance); Assert.IsFalse(monitor.TryTrade('MSFT', 1000), 'Monitor should block trade'); } }
public class TradeMonitor { private ILimitRepository repository; public TradeMonitor(ILimitRepository repository) { this.repository = repository; } public bool TryTrade(string symbol, int amount) { int limit = repository.GetLimit(symbol); int exposure = repository.GetExposure(symbol); return ((amount + exposure) <= limit); } }
33
WhichsoluVontouse?• BothServiceLocatorandDependencyInjec1onprovide
thedesireddecoupling• Withservicelocator,thedesidedcomponentisobtained
a\errequesttotheLocator• WithinjecVonthereisnoexplicitrequest:thecomponent
appearsintheapplicaVonclass• Inversionofcontrolabithardertounderstand• WithServiceLocatortheapplicaVonsVlldependsonthe
locator• Itiseasiertofinddependenciesofcomponentif
DependencyInjecVonisused– CheckconstructorsandseBersvscheckallinvocaVonstolocatorinthesourcecode
34
TowardsIoCContainers• TherearesVllsomeopenquesVons
– Whocreatesthedependencies?– WhatifweneedsomeiniValisaVoncodethatmustberuna\erdependencieshavebeenset?
– Whathappenswhenwedon’thaveallthecomponents?
• IoCContainerssolvetheseissues[eg:Spring]– HaveconfiguraVon–o\enexternal– Createobjects– EnsurealldependenciesaresaVsfied– Providelifecyclesupport
35
OtherpossiblesoluVons• Reflec1oncanbeusedtodeterminedependencies,reducingtheneedforconfigfiles.– Makecomponentsknowntocontainer.– Containerexaminesconstructorsanddeterminesdependencies.
• MostIoCcontainerssupportauto-wiring:automaVcwiringbetweenproperVesofabeanandotherbeansbased,eg,onnameortype
• Auto-wiringprovidesotherbenefits:– Lesstyping,especiallylongassemblynames.– StaVctypecheckingbyIDEateditVme.– MoreintuiVvefordeveloper.
36
IoCContainersandFeatures
Container Setter DI
Ctor DI
External config
Code config
Auto-wiring
Lifecycle support`
Url
System.ComponentModel a a Part of .Net framework
PicoContainer.Net a a a a a http://picocontainer.orgWindsor a a a ? a http://www.castleproject.orgStructureMap a a a P a http://sourceforge.net/projects/structuremapSpring.Net a a a ? a a http://www.springframework.net/ObjectBuilder a a a a ?? a http://msdn.microsoft.com
?? = More investigation
? = Setter based DI required for primitive dependenciesP = Partial still requires configuration to point to assemblies to scan
37
DependencyinjecVoninSpring• TheobjectsthatformthebackboneofaSpringapplicaVonare
calledbeans• AbeanisanobjectthatisinstanVated,assembled,andotherwise
managedbyaSpringIoCcontainer(Applica?onContext)• BeandefiniVoncontainstheinformaVoncalledconfigura1on
metadata,whichisneededforthecontainertoknowthefollowing– Howtocreateabean– Bean’slifecycledetails– Bean’sdependencies
• TheconfiguraVonmetadatacanbesuppliedtothecontainerinthreepossibleways:– XMLbasedconfigura1onfile(thestandard)– Annota1on-basedconfiguraVon– Java-basedconfiguraVon
38
SpringIoCcontainers• TheSpringcontainerisatthecoreoftheSpringFramework.• Thecontainerwillcreatetheobjects,wirethemtogether,
configurethem,andmanagetheircompletelifecyclefromcreaVonVlldestrucVon.
• TheSpringcontainerusesDependencyInjec1ontomanagethecomponentsthatmakeupanapplicaVon.
• ThecontainergetsitsinstrucVonsonwhatobjectstoinstanVate,configure,andassemblebyreadingtheconfigura1onmetadataprovided.
• TheconfiguraVonmetadatacanberepresentedeitherbyXML,JavaannotaVons,orJavacode.
• Thediagramtotherightrepresentsahigh-levelviewofhowSpringworks.TheSpringIoCcontainermakesuseofJavaPOJOclassesandconfiguraVonmetadatatoproduceafullyconfiguredandexecutablesystemorapplicaVon.
• QuicklybrowsingtheSpringArchitecture…https://docs.spring.io/spring/docs/3.0.x/reference/overview.html#overview-modules
39
//imports…publicclassMainApp{publicstaVcvoidmain(String[]args){ApplicaVonContextcontext=newClassPathXmlApplicaVonContext("Beans.xml");HelloWorldobj=(HelloWorld)context.getBean("helloWorld");obj.getMessage();}} Themainclass,loadinganApplica1onContext
40
publicclassHelloWorld{ privateStringmessage; publicvoidsetMessage(Stringmessage){ this.message=message; } publicvoidgetMessage(){ System.out.println("YourMessage:"+message); }} Thebean:aPOJO(PlainOldJavaObject)
<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="hBp://www.springframework.org/schema/beans"xmlns:xsi="hBp://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocaVon="hBp://www.springframework.org/schema/beanshBp://www.springframework.org/schema/beans/spring-beans-3.0.xsd”><beanid="helloWorld"class="com.tutorialspoint.HelloWorld"><propertyname="message"value="HelloWorld!"/></bean></beans> TheConfigura1onMetafile(XML)
SeBerInjecVon(performedbytheIoCcontainer)
So\wareFrameworkDesign
• IntellectualChallengingTask• Requiresadeepunderstandingoftheproblemdomain
• Requiresmasteringofso$ware(design)paZerns,OOmethodsandpolymorphisminparVcular
• Impossibletoaddressinthecourse,butwecanplayabit…
41
AFrameworkforthefamilyofDivideandConqueralgorithms
• Idea:startfromawell-knowngenericalgorithm• ApplyknowntechniquesandpaBernstodefineaframeworkforasoMwarefamily
• Instancesoftheframework,obtainedbystandardextensionmechanism,willbeconcretealgorithmsofthefamily
42
function solve (Problem p) returns Solution { if isSimple(p)! return simplySolve(p);! else!sp[] = decompose(p);!for (i= 0; i < sp.length; i = i+1)! sol[i] = solve(sp[i]);! return combine(sol);!}!
Frozen/HotSpotsandTemplateMethods• FrozenSpot:common(shared)aspectoftheso\ware
family• HotSpot:variableaspectofthefamily• Templatemethod:concretemethodofbaseclass
implemenVngbehaviorcommontoallmembersofthefamily
• Ahotspotisrepresentedbyagroupofabstracthookmethods.
• AtemplatemethodcallsahookmethodtoinvokeafuncVonthatisspecifictoonefamilymember.[InversionofControl]
• Ahotspotisrealizedinaframeworkasahotspotsubsystem.
43
TheUnificaVonPrinciple• Theunifica9onprincipleusesinheritancetoimplementthe
hotspotsubsystem.• Boththetemplatemethodsandhookmethodsaredefinedin
thesameabstractbaseclass.• Thehookmethodsareimplementedinsubclassesofthebase
class.Inthefigurebelow,thehotspotsubsystemfortheunificaVonapproachconsistsoftheabstractbaseclassanditssubclasses.
44
150 H.C. Cunningham et al. / Science of Computer Programming 59 (2006) 147–169
Fig. 1. Hot spot subsystem.
specific to one family member. Furthermore, we must separate the various common andvariable aspects from each other and consider them independently, one at a time. We usethe terms frozen spot to denote a common (or shared) aspect of the family and hot spot todenote a variable aspect of the family [22].A software framework is a generic application that allows the creation of different
specific applications from a family [21]. It is an abstract design that can be reused within awhole application domain. In a framework, the frozen spots of the family are representedby a set of abstract and concrete base classes that collaborate in some structure. A behaviorthat is common to all members of the family is implemented by a fixed, concrete templatemethod in a base class. A hot spot is represented by a group of abstract hook methods. Atemplate method calls a hook method to invoke a function that is specific to one familymember.A hot spot is realized in a framework as a hot spot subsystem. A hot spot subsystem
typically consists of an abstract base class, concrete subclasses of that base class, andperhaps other related classes [22]. The hook methods of the abstract base class define theinterface to the alternative implementations of the hot spot. The subclasses of the baseclass implement the hook methods appropriately for a particular choice for a hot spot.Fig. 1 shows a UML class diagram of a hot spot subsystem.There are two principles for framework construction—unification and separation [8].
The unification principle uses inheritance to implement the hot spot subsystem. Both thetemplate methods and hook methods are defined in the same abstract base class. The hookmethods are implemented in subclasses of the base class. In Fig. 1, the hot spot subsystemfor the unification approach consists of the abstract base class and its subclasses. Theseparation principle uses delegation to implement the hot spot subsystem. The templatemethods are implemented in a concrete context class; the hook methods are defined ina separate abstract class and implemented in its subclasses. The template methods thusdelegate work to an instance of the subclass that implements the hook methods. In Fig. 1,the hot spot subsystem for the separation approach consists of both the client (context)class and the abstract base class and its subclasses.A framework is a system that is designed with generality and reuse in mind; and
design patterns [9], which are well-established solutions to program design problemsthat commonly occur in practice, are the intellectual tools for achieving the desiredlevel of generality and reuse. Two design patterns, corresponding to the two frameworkconstruction principles, are useful in implementation of the frameworks.
TheSeparaVonPrinciple• Thesepara9onprincipleusesdelega1ontoimplementthe
hotspotsubsystem.• Thetemplatemethodsareimplementedinaconcretecontext
class;thehookmethodsaredefinedinaseparateabstractclassandimplementedinitssubclasses.
• Thetemplatemethodsthusdelegateworktoaninstanceofthesubclassthatimplementsthehookmethods.Inthefigurebelow,thehotspotsubsystemconsistsofboththeclient(context)classandtheabstractbaseclassanditssubclasses.
45
150 H.C. Cunningham et al. / Science of Computer Programming 59 (2006) 147–169
Fig. 1. Hot spot subsystem.
specific to one family member. Furthermore, we must separate the various common andvariable aspects from each other and consider them independently, one at a time. We usethe terms frozen spot to denote a common (or shared) aspect of the family and hot spot todenote a variable aspect of the family [22].A software framework is a generic application that allows the creation of different
specific applications from a family [21]. It is an abstract design that can be reused within awhole application domain. In a framework, the frozen spots of the family are representedby a set of abstract and concrete base classes that collaborate in some structure. A behaviorthat is common to all members of the family is implemented by a fixed, concrete templatemethod in a base class. A hot spot is represented by a group of abstract hook methods. Atemplate method calls a hook method to invoke a function that is specific to one familymember.A hot spot is realized in a framework as a hot spot subsystem. A hot spot subsystem
typically consists of an abstract base class, concrete subclasses of that base class, andperhaps other related classes [22]. The hook methods of the abstract base class define theinterface to the alternative implementations of the hot spot. The subclasses of the baseclass implement the hook methods appropriately for a particular choice for a hot spot.Fig. 1 shows a UML class diagram of a hot spot subsystem.There are two principles for framework construction—unification and separation [8].
The unification principle uses inheritance to implement the hot spot subsystem. Both thetemplate methods and hook methods are defined in the same abstract base class. The hookmethods are implemented in subclasses of the base class. In Fig. 1, the hot spot subsystemfor the unification approach consists of the abstract base class and its subclasses. Theseparation principle uses delegation to implement the hot spot subsystem. The templatemethods are implemented in a concrete context class; the hook methods are defined ina separate abstract class and implemented in its subclasses. The template methods thusdelegate work to an instance of the subclass that implements the hook methods. In Fig. 1,the hot spot subsystem for the separation approach consists of both the client (context)class and the abstract base class and its subclasses.A framework is a system that is designed with generality and reuse in mind; and
design patterns [9], which are well-established solutions to program design problemsthat commonly occur in practice, are the intellectual tools for achieving the desiredlevel of generality and reuse. Two design patterns, corresponding to the two frameworkconstruction principles, are useful in implementation of the frameworks.
H.C. Cunningham et al. / Science of Computer Programming 59 (2006) 147–169 153
Fig. 3. Template method for divide and conquer.
abstract public class DivConqTemplate{ public final Solution solve(Problem p)
{ Problem[] pp;if (isSimple(p)){ return simplySolve(p); }else { pp = decompose(p); }Solution[] ss = new Solution[pp.length];for(int i=0; i < pp.length; i++){ ss[i] = solve(pp[i]); }return combine(p,ss);
}abstract protected boolean isSimple (Problem p);abstract protected Solution simplySolve (Problem p);abstract protected Problem[] decompose (Problem p);abstract protected Solution combine(Problem p,Solution[] ss);
}
Fig. 4. Template method framework implementation.
as follows:
public interface Problem {};public interface Solution {};
Given the auxiliary types above, we define the abstract Template Method classDivConqTemplate as shown in Fig. 4. We generalize the combine()method to take boththe description of the problem and the subproblem solution array as arguments. The divide
Applyingtheunifica1onprinciple:
UMLdiagramofthesoluVon
46
function solve (Problem p) returns Solution { if isSimple(p)! return simplySolve(p);! else!sp[] = decompose(p);!for (i= 0; i < sp.length; i = i+1)! sol[i] = solve(sp[i]);! return combine(sol);!}!
47
function solve (Problem p) returns Solution { if isSimple(p)! return simplySolve(p);! else!sp[] = decompose(p);!for (i= 0; i < sp.length; i = i+1)! sol[i] = solve(sp[i]);! return combine(sol);!}!
H.C. Cunningham et al. / Science of Computer Programming 59 (2006) 147–169 153
Fig. 3. Template method for divide and conquer.
abstract public class DivConqTemplate{ public final Solution solve(Problem p)
{ Problem[] pp;if (isSimple(p)){ return simplySolve(p); }else { pp = decompose(p); }Solution[] ss = new Solution[pp.length];for(int i=0; i < pp.length; i++){ ss[i] = solve(pp[i]); }return combine(p,ss);
}abstract protected boolean isSimple (Problem p);abstract protected Solution simplySolve (Problem p);abstract protected Problem[] decompose (Problem p);abstract protected Solution combine(Problem p,Solution[] ss);
}
Fig. 4. Template method framework implementation.
as follows:
public interface Problem {};public interface Solution {};
Given the auxiliary types above, we define the abstract Template Method classDivConqTemplate as shown in Fig. 4. We generalize the combine()method to take boththe description of the problem and the subproblem solution array as arguments. The divide
H.C. Cunningham et al. / Science of Computer Programming 59 (2006) 147–169 153
Fig. 3. Template method for divide and conquer.
abstract public class DivConqTemplate{ public final Solution solve(Problem p)
{ Problem[] pp;if (isSimple(p)){ return simplySolve(p); }else { pp = decompose(p); }Solution[] ss = new Solution[pp.length];for(int i=0; i < pp.length; i++){ ss[i] = solve(pp[i]); }return combine(p,ss);
}abstract protected boolean isSimple (Problem p);abstract protected Solution simplySolve (Problem p);abstract protected Problem[] decompose (Problem p);abstract protected Solution combine(Problem p,Solution[] ss);
}
Fig. 4. Template method framework implementation.
as follows:
public interface Problem {};public interface Solution {};
Given the auxiliary types above, we define the abstract Template Method classDivConqTemplate as shown in Fig. 4. We generalize the combine()method to take boththe description of the problem and the subproblem solution array as arguments. The divide
Codeoftheframework(unifica?onprinciple)
48
H.C. Cunningham et al. / Science of Computer Programming 59 (2006) 147–169 155
public class QuickSort extends DivConqTemplate{ protected boolean isSimple (Problem p)
{ return ( ((QuickSortDesc)p).getFirst() >=((QuickSortDesc)p).getLast() );
}protected Solution simplySolve (Problem p){ return (Solution) p ; }protected Problem[] decompose (Problem p){ int first = ((QuickSortDesc)p).getFirst();
int last = ((QuickSortDesc)p).getLast();int[] a = ((QuickSortDesc)p).getArr ();int x = a[first]; // pivot valueint sp = first;for (int i = first + 1; i <= last; i++){ if (a[i] < x) { swap (a, ++sp, i); } }swap (a, first, sp);Problem[] ps = new QuickSortDesc[2];ps[0] = new QuickSortDesc(a,first,sp-1);ps[1] = new QuickSortDesc(a,sp+1,last);return ps;
}protected Solution combine (Problem p, Solution[] ss){ return (Solution) p; }private void swap (int [] a, int first, int last){ int temp = a[first];
a[first] = a[last];a[last] = temp;
}}
Fig. 6. Quicksort application.
3.3. Constructing a framework using separation
As an alternative to the above design, we can use the separation principle and Strategypattern to implement a divide and conquer framework. The UML class diagram for this ap-proach is shown in Fig. 7. The template method is implemented in the (concrete) contextclass DivConqContext as shown in Fig. 8. The hook methods are defined in the (abstract)Strategy class DivConqStrategy as shown in Fig. 9. The context class delegates the hookmethod calls to a reference to the instance of the Strategy class that it stores internally. Notethat the Strategy approach is more flexible than the Template Method approach in that it ispossible to switch Strategy objects dynamically by using the setAlgorithm()method ofthe context class. Constructing an application of the Strategy-based framework for Quick-sort requires that we implement a subclass of the abstract class DivConqStrategy that isquite similar to the QuickSort class used in the unification framework (shown in Fig. 6).The divide and conquer family of algorithms is a simple example that can be used
to illustrate both approaches to framework design. It consists of a set of algorithms thatshould be known to the students. Hence, the application domain should be easy to explain.In the associated project, students can be given the framework and asked to construct
154 H.C. Cunningham et al. / Science of Computer Programming 59 (2006) 147–169
public class QuickSortDesc implements Problem, Solution{ public QuickSortDesc(int[]arr, int first, int last)
{ this.arr = arr; this.first = first; this.last = last; }public int getFirst () { return first; }public int getLast () { return last; }private int[] arr; // instance dataprivate int first, last;
}
Fig. 5. Quicksort Problem and Solution implementation.
and conquer framework thus consists of the DivConqTemplate class and the Problemand Solution interfaces. We can now consider an application built using this frameworklibrary.
3.2. Building an application of the framework
In using a traditional procedure or class library, a client’s program is in control of thecomputation; it “calls down” to code from the library. However, frameworks usually exhibitan inversion of control. The framework’s code is in control of the computation; its templatemethods “call down” to the client-supplied hook methods. This section illustrates the useof the divide and conquer framework to build a quicksort application.Quicksort is an in-place sort of a sequence of values. The description of a problem
consists of the sequence of values and designators for the beginning and ending elementsof the segment to be sorted. To simplify the presentation, we limit its scope to integerarrays. Therefore, it is sufficient to identify a problem by the array and the beginning andending indices of the unsorted segment. Similarly, a solution can be identified by the arrayand the beginning and ending indices of the sorted segment. This similarity between theProblem and Solution descriptions enables us to use the same object to describe both aproblem and its corresponding solution. Thus, we introduce the class QuickSortDesc todefine the needed descriptor objects as shown in Fig. 5. Given the definitions for base classDivConqTemplate and auxiliary class QuickSortDesc, we can implement the concretesubclass QuickSort as shown in Fig. 6.In a teaching module using this case study, both the framework (i.e., the abstract class)
and the framework application (i.e., the implementation of quicksort) can be presentedto the students so that they can discern the collaborations and relationships among theclasses clearly. However, a clear distinction must be made between the framework andits application. As an exercise, the students can be assigned the task of modifying thequicksort application to handle more general kinds of objects. Other algorithms such asmergesort and binary search should also be assigned as exercises. The amount of workthat each hook method has to do differs from one specific algorithm to another. In thequicksort implementation, most of the work is done in the decompose() method, whichimplements the splitting or pivoting operation of quicksort. In mergesort, however, morework will be done in the combine() operation because it must carry out the merge phaseof the mergesort algorithm.
AnapplicaVonoftheframework:
QuickSort(unifica?onprinciple)
Applyingthesepara1onprinciple:
UMLdiagramofthesoluVon
49
function solve (Problem p) returns Solution { if isSimple(p)! return simplySolve(p);! else!sp[] = decompose(p);!for (i= 0; i < sp.length; i = i+1)! sol[i] = solve(sp[i]);! return combine(sol);!}!
156 H.C. Cunningham et al. / Science of Computer Programming 59 (2006) 147–169
Fig. 7. Strategy pattern for divide and conquer framework.
public final class DivConqContext{ public DivConqContext (DivConqStrategy dc)
{ this.dc = dc; }public Solution solve (Problem p){ Problem[] pp;
if (dc.isSimple(p)) { return dc.simplySolve(p); }else { pp = dc.decompose(p); }Solution[] ss = new Solution[pp.length];for (int i = 0; i < pp.length; i++){ ss[i] = solve(pp[i]); }return dc.combine(p, ss);
}public void setAlgorithm (DivConqStrategy dc){ this.dc = dc; }private DivConqStrategy dc;
}
Fig. 8. Strategy context class implementation.
abstract public class DivConqStrategy{ abstract public boolean isSimple (Problem p);
abstract public Solution simplySolve (Problem p);abstract public Problem[] decompose (Problem p);abstract public Solution combine(Problem p, Solution[] ss);
}
Fig. 9. Strategy object abstract class.
50
Codeoftheframework(separa?onprinciple)
156 H.C. Cunningham et al. / Science of Computer Programming 59 (2006) 147–169
Fig. 7. Strategy pattern for divide and conquer framework.
public final class DivConqContext{ public DivConqContext (DivConqStrategy dc)
{ this.dc = dc; }public Solution solve (Problem p){ Problem[] pp;
if (dc.isSimple(p)) { return dc.simplySolve(p); }else { pp = dc.decompose(p); }Solution[] ss = new Solution[pp.length];for (int i = 0; i < pp.length; i++){ ss[i] = solve(pp[i]); }return dc.combine(p, ss);
}public void setAlgorithm (DivConqStrategy dc){ this.dc = dc; }private DivConqStrategy dc;
}
Fig. 8. Strategy context class implementation.
abstract public class DivConqStrategy{ abstract public boolean isSimple (Problem p);
abstract public Solution simplySolve (Problem p);abstract public Problem[] decompose (Problem p);abstract public Solution combine(Problem p, Solution[] ss);
}
Fig. 9. Strategy object abstract class.
156 H.C. Cunningham et al. / Science of Computer Programming 59 (2006) 147–169
Fig. 7. Strategy pattern for divide and conquer framework.
public final class DivConqContext{ public DivConqContext (DivConqStrategy dc)
{ this.dc = dc; }public Solution solve (Problem p){ Problem[] pp;
if (dc.isSimple(p)) { return dc.simplySolve(p); }else { pp = dc.decompose(p); }Solution[] ss = new Solution[pp.length];for (int i = 0; i < pp.length; i++){ ss[i] = solve(pp[i]); }return dc.combine(p, ss);
}public void setAlgorithm (DivConqStrategy dc){ this.dc = dc; }private DivConqStrategy dc;
}
Fig. 8. Strategy context class implementation.
abstract public class DivConqStrategy{ abstract public boolean isSimple (Problem p);
abstract public Solution simplySolve (Problem p);abstract public Problem[] decompose (Problem p);abstract public Solution combine(Problem p, Solution[] ss);
}
Fig. 9. Strategy object abstract class.