Post on 18-Mar-2018
transcript
I’msensingapattern
TonyVeale2018
SsshhhhGreatartistssteal…
Help!
Whenwerefertotheideaof“genre”or“style”or
“paradigm”inArt,ScienceorCommercialDesign,wearereferringtotheideaof
DesignPatterns…
Thesecodifytheunspokennormsofgooddesign,andapplyinmanydisciplines.
ReneMagritte’sDesignPatterns
(1928)
HowshouldIorganizemyclasses?
Be Wise! Use the
Luke.
Be Wise! Use the
Luke.
…andthreatenitwithimminent
destructionbyaninventivemeans.
Wemeetagain,Mr.Bond…
CompartmentalizeresponsibilityMaximizecoherencewithin
compartmentsMinimizedependenciesbetween
compartmentsReduceredundancy&inefficiencyExplicitlyassignresponsibilitiesOrderlyflowofinformation
Scalability&Extensibility
Soalone
Differentparameterizedconfigurationsofthesameclassareinstantiatedtosuitdifferentcontextsanduses.
Flippin’
Nora,that’saBig‘Un…
Therecanbeonlyonesilverback.
publicinterfaceQuantifiableextendsIdentifiable{
publicintgetQuantity();
publicintaddQuantity(intdelta);
publicintremoveQuantity(intdelta);
}
Let’sstartbydefininganInterfacetypefortrackingtheingredientsinourrestaurant’spantry…
Cleanthatfridge!
publicinterfaceManageable{
publicQuantifiablelookup(Stringidentifier);
publicQuantifiableadd(Quantifiableentry);
publicvoidremove(Quantifiableentry);
}
NowaddanInterfacetypeforbringingallofthisstocktogetherintoaManageablesystem…
InventoryControl!
importjava.util.Hashtable;
publicclassCentralPantryimplementsManageable{
privateHashtable<String,Quantifiable>store=null;
privateCentralPantry(){
store=newHashtable<String,Quantifiable>();}}
Wecannowbegintoimplementourcentralpantry.Butwhydoesourclassrequireaprivateconstructor?
privatestaticCentralPantrycache=null;
publicstaticsynchronizedCentralPantrygetPantry(){ if(cache==null)
cache=newCentralPantry();
returncache; }
Onlyaclassinstancecancallaprivateconstructor.Soprovideastaticmethodtoinstantiatetheclass.
Sousethestaticmethod,andnottheconstructor
publicclassCentralPantryimplementsManageable{
publicstaticCentralPantrygetPantry(){ returnSingletonCache.ONE;}privatestaticclassSingletonCache{
publicstaticfinalCentralPantryONE=newCentralPantry();
}
privateCentralPantry(){…}
OR:WecanexploitJava’slazyevaluationofassignmentsJavalazilyloadsclassesonlyastheyareneeded…
staticgetInstance()singletonOperations()getSingletonData()
staticuniqueInstancesingletonData
returnuniqueInstance;
Here’stheSingletonpatterninanutshell.
P1
P2
P3
P4
P5 P6
P8
P7
P9
P0
P10
P11
Whenaclasshasacomplicated,multi-stepsetupprocedure,andadiversityofconfigurationoptions,thenitmakessensetodefineanotherclass,calledaBuilder,whoseresponsibilityisthe
constructionofnewinstances ofthemorecomplexclass.
Take,forexample,themakingofapizza…
publicclassCommodityimplementsQuantifiable{ privateStringidentifier=null; privateintamount=1; publicCommodity(Stringname){ identifier=name; } publicStringgetIdentifier(){ returnidentifier; }
First,let’screatethemostgenericandreusablesetofclassesandinterfacesforourourexample…
Continuedoverleaf…
Pizzasarecommodities
publicintgetQuantity(){ returnamount; } publicintaddQuantity(intdelta){ amount+=delta; returnamount; } publicintremoveQuantity(intdelta){ amount+=delta; returnamount; }}
ImplementQuantifiableinterface
publicinterfaceBakeable{ publicvoidsetDough(Quantifiabledough); publicvoidaddSauce(Quantifiablesauce); publicvoidaddTopping(Quantifiabletopping); }
BeforedefiningaPizzaclass,generalizetothecategoryofallbakeablecommodities…
Pizzasimplementthesemethods
publicclassPizzaextendsCommodityimplementsBakeable{
privateQuantifiabledough=null,sauce=null; Vector<Quantifiable>toppings
=newVector<Quantifiable>(); publicPizza(Stringname){ super(name); }
NowwedefinePizzaastheclassofbakeablecommodities
Continuedoverleaf…
publicvoidsetDough(Quantifiabledough){ this.dough=dough; } publicvoidaddSauce(Quantifiablesauce){ this.sauce=sauce; } publicvoidaddTopping(Quantifiabletopping){ toppings.add(topping); }}
ImplementBakeablerequirementsforpizzavariations
publicinterfaceSubcontractable{ publicvoidbuildSequence(); publicvoidstartProduct(Stringname);
publicCommoditygetProduct();}
Asubcontractorisabuildertowhichwedelegatejobs.EachsubcontractormustimplementSubcontractable…
Ourpizzabuilderswillimplementthis
publicinterfaceContractable{ publicvoidsetSubcontractor(Subcontractable
subcontractor); publicCommoditydeliverContract();}
AContractorcanformacontractwithasubcontractortodeliveronacontractforacommoditywithaclient….
Thinkofthelinkbetweenachefandasouschef
abstractpublicclassPizzaBuilderimplementsSubcontractable{
privatePizzapizza=null; publicvoidbuildSequence(){ buildDough(); buildSauce(); buildToppings(); }
APizzaBuilderisasubcontractableclassthatcombinesspecificdough,sauceandtoppingstomakeapizza
Continuedoverleaf…
publicCommoditygetProduct(){ returnpizza; }
publicvoidstartProduct(Stringname){ pizza=newPizza(name); }
abstractpublicvoidbuildDough();
abstractpublicvoidbuildSauce();
abstractpublicvoidbuildToppings();}
Abstractmethodsmustbeimplementedbyspecificbuilders
publicclassHawaiianBuilderextendsPizzaBuilder{ publicvoidbuildDough(){ startProduct(“Hawaiian”);
((Bakeable)getProduct()).setDough(newCommodity("thincrust"));
} publicvoidbuildSauce(){ ((Bakeable)getProduct())
.addSauce(newCommodity("marinara")); } publicvoidbuildToppings(){ ((Pizza)getProduct()).setDough(new
Let’slookataspecificbuilderforaspecifickindofpizza…
Continuedoverleaf…
publicvoidbuildToppings(){
((Bakeable)getProduct()).addTopping(newCommodity("Mozzarella"));
((Bakeable)getProduct())
.addTopping(newCommodity("ham"));
((Bakeable)getProduct()) .addTopping(newCommodity("pineapple"));
}}
Aspecificbuilderappliesspecificelementstothebuild
publicclassPizzaContractorimplementsContractable{ privatePizzaBuildersubcontractor=null; publicvoidsetSubcontractor(Subcontractable
subcontractor){ this.subcontractor=(PizzaBuilder)subcontractor; } publicCommoditydeliverContract(){ subcontractor.buildSequence(); returnsubcontractor.getProduct(); }
APizzaContractordeliversonacontractforapizza
Continuedoverleaf…
publicstaticvoidmain(String[]args){
PizzaBuildersouschef=newHawaiianBuilder();
Contractablechef=newPizzaContractor();
chef.setSubcontractor(souschef);
Commoditypizza=chef.deliverContract();
if(pizza.getIdentifier()=="Hawaiian") System.out.println("Aloha!");}
}
Atlastwecreateacontractorandasubcontractorforpizza
ALOHA!
ExpertBuilder
+startProduct()+getProduct()
ExpertBuilder
+startProduct()+getProduct()
Subcontractor
buildSequence()
Contractor
deliverContract()
Commodity
ExpertBuilder
+startProduct()+getProduct()
forallaspectsofschemesubcontractor.buildSequence();
Exemplar1
+startProduct()+getProduct()
Exemplar1
+startProduct()+getProduct()
Exemplar1
+startProduct()+getProduct()
Exemplar1
+startProduct()+getProduct()
Commodity
clone()
Contractor
prototype
deliverContract()
Exemplar1
clone()
ExemplarN
clone()
returnprototype.clone();
publicstaticvoidmain(String[]args){
Pizzahawaiian=newPizza("MagnumP.I.");
hawaiian.setDough(newCommodity("thincrust"));
hawaiian.addSauce(newCommodity("barbecue"));
hawaiian.addTopping(newCommodity("ham"));
hawaiian.addTopping(newCommodity("mushroom"));
hawaiian.addTopping(newCommodity("pineapple"));
Let’sbuildaHawaiianpizzadirectly,withNoBuilderclass
Pizzasicilian=newPizza("TheGodfather");
sicilian.setDough(newCommodity("deeppan"));
sicilian.addSauce(newCommodity("spicy"));
sicilian.addTopping(newCommodity("salami"));
sicilian.addTopping(newCommodity("pepperoni"));
sicilian.addTopping(newCommodity("chilies"));
sicilian.addTopping(newCommodity("blackolives"));
Nowbuildanotherprototypepizza,withNoBuilderclass
publicCommodityclone(){ try{ return(Commodity)super.clone(); }catch(Exceptione){ returnnull; } }
IntheCommodityclasswedefineamethodto“clone”acommodity,catchinganyexceptionsthatarethrown…
A“clone”isacopyofanobjectwiththesame(==)field
values
publicclassCommodityContractorimplementsContractable{
privateCommoditystyle=null; publicvoidsetStyle(Commodityexemplar){ this.style=exemplar; }
publicvoidsetSubcontractor(Subcontractablesub){}; publicCommoditydeliverContract(){ returnstyle.clone(); }}
WecansimplifyourContractorclassesgreatlynow…
CommodityContractorchef=newCommodityContractor();
chef.setStyle(sicilian);
CommoditymyPizza=chef.deliverContract();
System.out.println(myPizza.getIdentifier());
chef.setStyle(hawaiian);
myPizza=chef.deliverContract();
System.out.println(myPizza.getIdentifier());
Let’srevisitourpizza-makingexampleviaourPrototypes
“MagnumP.I.”
“TheGodfather”
NoticehowtheSingleton,BuilderandPrototypepatternsalterthewayweviewclassinstantiation.
Wherepossible,wedelegatethisresponsilibitytoexpertswhohide
(byencapsulation)thetruecomplexityofobjectcreation.
Iprefermy
pizzatobemadebyanexpert!
CommodityContractorchef=newCommodityContractor();
chef.setStyle(sicilian);
Contractablechef=newPizzaContractor();
chef.setSubcontractor(hawaiianChef);
NoticehowinboththeBuilderandPrototypeweuseinterfacestominimizedependenciesbetweencontractorandsubcontractor…Weinjectthesedependencieslateinthegame
SomedevelopersconsiderDependencyInjectiontobeadesignpatterninitsownright.Whatisclearisthatitisakeypartofmanyotherdependency-reducingpatterns.
Wecallthisstrategy
DependencyInjection
Whenwewantafamilyofrelatedbuildersthatconstructathematically-consistentfamilyofrelatedcommodities
AfactoryofGUIwidgetsforMACOScanreplace
AfactoryofGUIwidgetsforWindows.
Factory_Style1
getPart1(),…,getPartN(),
Factory_Style1
getPart1(),…,getPartN(),
Factory_Style1
getPart1(),…,getPartN(),
Factory
getPart1(),…,getPartN(),
Consumer
factory
useParts()
Factory_Style_1
getPart1(),…,getPartN(),
Factory_Style_N
getPart1(),…,getPartN(),
publicclassPizzaFactoryextendsPizzaContractor{ publicCommoditygetPizza(){ returndeliverContract(); } publicCommoditygetSandwich(){ Pizzapie=(Pizza)deliverContract(); pie.setDough(newCommodity("crustyroll")); returnpie; }
Let’sturnourPizzamakerintoaFactoryofItaliandishes
Continuedoverleaf…
publicCommoditygetCalzone(){ Pizzapie=(Pizza)deliverContract();
pie.setDough(newCommodity("foldedcrust"));
returnpie; } publicCommoditygetLasagne(){ Pizzapie=(Pizza)deliverContract();
pie.setDough(newCommodity("lasangasheets"));
returnpie; }}
Addcalzonesandevenlasagnesforgoodmeasure…
publicstaticvoidmain(String[]args){
PizzaBuilderstylist=newHawaiianBuilder();
PizzaFactoryfactory=newPizzaFactory();
factory.setSubcontractor(stylist);
Commoditylunch=factory.getSandwich();
if(lunch.getIdentifier()=="Hawaiian") System.out.println("TheEnd");}
}
Nowourpizzafactorymakesthematicallyconsistentdishes
TheEnd