Design patterns: An Introduction to Software Design Patterns

Post on 18-Mar-2018

83 views 9 download

Transcript of Design patterns: An Introduction to Software Design Patterns

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