Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design...

151

Transcript of Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design...

Page 1: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed
Page 2: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

Contents

DesignPatternsinSwiftStoryShopCopyrightHalfTitlePrefaceIntroductionPartOne-SOLID1)SOLID-SingleResponsibilityPrinciple(SRP)2)SOLID-OpenClosedPrinciple(OCP)3)SOLID-LiskovSubstitutionPrinciple(LSP)4)SOLID-InterfaceSegregationPrinciple(ISP)5)SOLID-DependencyInversionPrinciple(DIP)PartTwo-Creational6)Creational-FactoryDesignPattern8)Creational-PrototypeDesignPattern9)Creational-SingletonDesignPatternPartThree-Structural10)Structural-AdapterDesignPattern11)Structural-BridgeDesignPattern12)Structural-CompositeDesignPattern13)Structural-DecoratorDesignPattern14)Structural-FacadeDesignPattern15)Structural-FlyWeightDesignPattern16)Structural-ProxyDesignPatternPartFour-Behavioural17)Behavioural-ChainofResponsibilityDesignPattern18)Behavioural-StrategyDesignPattern20)Behavioural-IteratorDesignPattern21)Behavioural-InterpreterDesignPattern22)Behavioural-MediatorDesignPattern23)Behavioural-MementoDesignPattern24)Behavioural-NullObjectDesignPattern25)Behavioural-ObserverDesignPattern26)Behavioural-StateDesignPattern27)Behavioural-TemplateDesignPattern

Page 3: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

28)Behavioural-VisitorDesignPatternFinalnote:

Page 4: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

DesignPatternsinSwift

VamshiKrishna

(Non)FictionVortex™

Page 5: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

JointheStorywithourgroundbreakingmobileapp,

StoryShop.Weareredefiningdigitalnarrative.

Page 6: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

DesignPatternsinSwiftVamshiKrishna

ElectronicEditionCopyright©2018byFictionVortex.Allrightsreserved.PrintEditionCopyright©2018byFictionVortex.Allrightsreserved.

Nopartofthispublicationmaybereproduced,storedinaretrievalsystem,ortransmittedinanywaybyanymeans,electronic,mechanical,photocopy,recordingorotherwisewithoutthepriorpermissionoftheauthorexceptasprovidedbyUSAcopyrightlaw.

ISBN:978-1-947655-16-4PublishedbyFictionVortex,Inc.(FVPress)Nampa,ID83651http://www.fictionvortex.com

CoverbyTomPatchin

PublishedintheUnitedStatesofAmerica

Page 7: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

DesignPatternsinSwift

VamshiKrishna

Page 8: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

Preface

DesignPatterns-Icameacrossthistermforthefirsttimeinmylifeinajobinterview(mindyou,IwasalmosttwoyearsintoiOSDevelopmentthen).Igotbackhomeandgoogledaboutthem.Itwasembarrassingandinterestingatthesametime,asIfoundoutthatIhadbeenusingafewofthosepatternswithoutactuallyrealisingthatIwasdoingso.

Iforgotaboutthatincidentafterseveraldaysandgotbacktomywork.Fastforwardtwoyears,IwasbackatjobsearchingandthistimeIdecidedtolearnindepthaboutdesignpatterns.AsaseasonediOSDeveloper,IwasinitiallylookingtolearntheconceptsthroughexamplescodedinSwiftlanguage.

Surprisingly,IcouldnotfindasinglebookorblogdiscussingdesignpatternsindetailintheSwiftlanguage.TherearetonsofbooksandblogsdiscussingtheminJava,C#,PHP,etc.

ForsomeonewhocodesinSwift,itonlytakesalittleefforttounderstandJava.So,IstartedlearningthedesignpatternsfromdifferentsourcesavailableontheInternetthroughJavaexamples.Forpractice,IstartedputtingupafewexamplesinSwiftforeachofthedesignpatterns.

Personally,cricketissomethingthatIunderstandinandout.Icanalmostrelateanythingunderthesuntoasituationincricket(okay,that’sabitofanexaggeration).

So,Idecided,insteadofusingdifferentcontextsforeachofthedesignpatternexamples,IwouldbeusingcricketingtermsforalltheexamplesIwouldbecoding.Ibelievecricketisaverysimplegame,andevenforthosewhodonotfollowthegame,itshouldnotbeabigefforttorelatetothecricketingterms.

Page 9: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

That’swhenIdecidedinsteadofjustlettingthecoderesideonmyMac,Iwouldputalittlemoreefforttotakeittobookform.That’showthisbookwasborn,andIamsureyourunderstandingondesignpatternswillbeenhancedbythetimeyoufinishreadingthisbook.

Iwouldsuggestyoucodetheexamples(notcopy-paste,buttypeeachandeverylineofthecode)inyourXcodeplaygroundandseetheresultsforyourself.Thenimagineascenariowhereyouwouldapplysuchadesignpattern,andcodeanexampleforyourself.

Ibelievethat’showcodingislearned.

Happylearning.

Page 10: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

Introduction

Wikipediasays,“Insoftwareengineering,asoftwaredesignpatternisageneral,reusablesolutiontoacommonlyoccurringproblemwithinagivencontextinsoftwaredesign”.

Inageneralsense,designpatternscanbestatedasbestpracticesthatwereimplementedonarepetitivebasistosolvesimilarproblems,butthatarefoundindifferentcontexts.

Designpatternsarenotfinisheddesignsthatcanbedirectlytransformedintocode.Butthetemplatescanhelpasabridgebetweenthelevelsofaprogrammingparadigmandconcretealgorithm.Thesetemplatescanalsobeusedtosolveaspecifictypeofproblemthatcanoccurindifferentprogrammingsituations.

ThepopularityofdesignpatternscameaboutafterbeingformalisedinthebookDesignPatterns:ElementsofReusableObject-OrientedSoftwarebytheso-calledGangofFour.

DesignpatternsareverypopularinJavaandC#,buttheycanbeappliedtoallobjectorientedlanguages.Theyareuniversallyrelevantbecausewearelivinginaworldwhereobjectorientedparadigmsareusedonadailybasis.Objectorienteddesignpatternsmainlyshowstheinteractionsandrelationshipsbetweenclassesorobjects.

Interestingly,mostdevelopershavebeenusingdesignpatterns(atleastafewofthem)formanyyearswithoutactuallyrealisingthattheyaredoingso.

Designpatternsonabroadlevelcanbedividedintofourtypes,namely:

Page 11: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

1. SOLIDDesignPrinciples2. Creational3. Structural4. Behavioural

SOLIDdesignprinciples,introducedbyRobertC.Martin,arerelevantacrossalloftheremainingthreedesignpatterns.SOLIDisanacronymforthesetoffivedesignprinciplesintendedtomakesoftwaredesignsmoreunderstandable,flexible,andmaintainable.It’sbettertobeawareofthembeforemovingontotheotherpatterns.

Prerequisites:

1. BasicunderstandingofSwift2. Goodunderstandingofobjectorientedprogramming

Contents:

1. SOLID-SingleResponsibilityPrinciple2. SOLID-OpenClosedPrinciple3. SOLID-LiskovSubstitutionPrinciple4. SOLID-InterfaceSegregationPrinciple5. SOLID-DependencyInversionPrinciple6. Creational-FactoryDesignPattern7. Creational-BuilderDesignPattern8. Creational-PrototypeDesignPattern9. Creational-SingletonDesignPattern10. Structural-AdapterDesignPattern11. Structural-BridgeDesignPattern12. Structural-CompositeDesignPattern13. Structural-DecoratorDesignPattern14. Structural-FacadeDesignPattern15. Structural-FlyWeightDesignPattern

Page 12: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

16. Structural-ProxyDesignPattern17. Behavioural-ChainofResponsibilityDesignPattern18. Behavioural-StrategyDesignPattern19. Behavioural-CommandDesignPattern20. Behavioural-IteratorDesignPattern21. Behavioural-InterpreterDesignPattern22. Behavioural-MediatorDesignPattern23. Behavioural-MementoDesignPattern24. Behavioural-NullObjectDesignPattern25. Behavioural-ObserverDesignPattern26. Behavioural-StateDesignPattern27. Behavioural-TemplateDesignPattern28. Behavioural-VisitorDesignPattern

Page 13: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

PartOne:SOLID

Page 14: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

1)SOLID-SingleResponsibilityPrinciple(SRP)Definition:

Singleresponsibilityprinciplesaysaclassshouldhaveone,andonlyone,reasontochange.Everyclassshouldberesponsibleforasinglepartofthefunctionality,andthatresponsibilityshouldbeentirelyencapsulatedbytheclass.Thismakesyoursoftwareeasiertoimplementandpreventsunexpectedside-effectsoffuturechanges.

Usage:

Letusdesignanimaginaryoperationsystemforacrickettournament.Forthesakeofsimplicity,let’shavetwomajoroperations:1)ATeamRegisterclass,whichhelpsforcheckinginandcheckingoutcricketers.2)ATeamConveyanceclass,whichisusedtodroptheplayersfromhoteltostadiumandtopickthemupfromthestadiumafterthematchisover.

Everyclassisassigneditsownresponsibilityandtheywillberesponsibleonlyforthataction.

importUIKitimportFoundation

classTeamRegister:CustomStringConvertible{

varteamMembers=[String]()varmemberCount=0funccheckInGuest(_name:String)->Int{

Page 15: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

memberCount+=1teamMembers.append("\(memberCount)-\(name)")returnmemberCount-1}funccheckOutGuest(_index:Int){teamMembers.remove(at:index)}vardescription:String{returnteamMembers.joined(separator:"\n")}}

TeamRegisterclassconformstoCustomStringConvertible.Ithastwovariablesdefined,anarraynamedteamMembersoftypeStringandmemberCountoftypeInteger.

Wealsodefinetwomethods.checkInGuestmethodtakestheguestnameasaparameteroftypeStringandappendstheguesttoteamMembersarrayandreturnsarraycount.

checkOutGuesttakesindexoftypeIntegerasaparameterandremovestheguestfromregister.

classTeamConveyance{functakePlayersToStadium(_teamRegister:TeamRegister){print("Takingplayers\n\(teamRegister.description)\ntotheStadium")}funcdropPlayersBackAtHotel(){print("DroppingalltheplayersbackatHotel")}}

TeamConveyanceclasshastwomajorresponsibilities.takePlayersToStadiumtakesaparameteroftypeTeamRegisteranddropsalltheplayersatthestadium.

Page 16: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

dropPlayersBackAtHotelgetsbackalltheplayerstothehotelafterthematchisover.Itisnotconcernedaboutanythingelse.

Letusnowwriteafunctioncalledmainandseethecodeinaction.

funcmain(){letteamRegister=TeamRegister()letplayer1=teamRegister.checkInGuest("PlayerOne")letplayer2=teamRegister.checkInGuest("PlayerTwo")print(teamRegister)}

main()

WetakeaninstanceofTeamRegisterclassandcheckinacoupleofguestspassingtheirnamesasparameters.

OutputintheXcodeconsole:

1-PlayerOne2-PlayerTwo

Letusnowcheckoutaguestandaddonemoreguesttotheteam.Changethemainfunctionto:

funcmain(){letteamRegister=TeamRegister()letplayer1=teamRegister.checkInGuest("PlayerOne")letplayer2=teamRegister.checkInGuest("PlayerTwo")print(teamRegister)teamRegister.checkOutGuest(1)print("------------------------------------")print(teamRegister)letplayer3=teamRegister.checkInGuest("PlayerThree")

Page 17: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

print("------------------------------------")print(teamRegister)}

main()

Wecheckedout‘PlayerTwo’andthencheckedinanotherguestnamed‘PlayerThree’.

OutputintheXcodeconsole:

1-PlayerOne2-PlayerTwo------------------------------------1-PlayerOne------------------------------------1-PlayerOne3-PlayerThree

Nowchangethemainmethodtothefollowing:

funcmain(){letteamRegister=TeamRegister()letplayer1=teamRegister.checkInGuest("PlayerOne")letplayer2=teamRegister.checkInGuest("PlayerTwo")print(teamRegister)teamRegister.checkOutGuest(1)print("------------------------------------")print(teamRegister)letplayer3=teamRegister.checkInGuest("PlayerThree")

print("------------------------------------")print(teamRegister)print("------------------------------------")letteamBus=TeamConveyance()

Page 18: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

teamBus.takePlayersToStadium(teamRegister)print("-------MatchOver----------")teamBus.dropPlayersBackAtHotel()}

main()

WearetakinganinstanceofTeamConveyancetodropplayersatthestadiumandgetthembacktothehotelafterthematchisover.

OutputintheXcodeconsole:

1-PlayerOne2-PlayerTwo------------------------------------1-PlayerOne------------------------------------1-PlayerOne3-PlayerThree------------------------------------Takingplayers1-PlayerOne3-PlayerThreetotheStadium-------MatchOver----------DroppingalltheplayersbackatHotel

Page 19: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

2)SOLID-OpenClosedPrinciple(OCP)Definition:

Openclosedprinciplesaysoneshouldbeabletoextendaclassbehaviourwithoutmodifyingit.Thisprincipleisthefoundationforbuildingcodethatismaintainableandreusable.

AnyclassfollowingOCPshouldfulfilltwocriteria:

1. 1) Openforextension:Thisensuresthattheclassbehaviourcanbeextended.Inarealworldscenario,requirementskeepchanging,andinorderforustobeabletoaccommodatethosechanges,classesshouldbeopenforextensionsothattheycanbehaveinanewway.

1. 2) Closedformodification:Codeinsidetheclassiswritteninsuchawaythatnooneisallowedtomodifytheexistingcodeunderanycircumstances.

Usage:

Letusconsideranexamplewherewehaveanarrayofcricketers’profiles,whereeachentityhasthenameofacricketer,histeam,andhisspecialisationastheattributes.Nowwewanttobuildasystemwheretheclientcanapplyfiltersonthedatabasedondifferentcriterialiketeam,roleoftheplayer,etc.LetusseehowwecanuseOCPtobuildthis:

importFoundationimportUIKit

Page 20: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

enumTeam{caseindiacaseaustraliacasepakistancaseengland}

enumRole{casebatsmancasebowlercaseallrounder}

Enumerationisadatatypethatallowsustodefinealistofpossiblevalues.Wedefineenumsfortheavailablenamesoftheteamsandrolesofthecricketers.

classCricketer{varname:Stringvarteam:Teamvarrole:Roleinit(_name:String,_team:Team,_role:Role){self.name=nameself.team=teamself.role=role}}

WethendefineaclasscalledCricketer,whichtakesthreeparametersduringitsinitialisation:nameoftypeString,teamoftypeTeam,androleoftypeRole.

Now,assumeoneoftheclientrequirementsistoprovideafilterofcricketersbasedontheirteam.

classCricketerFilter{

Page 21: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcfilterByTeam(_cricketers:[Cricketer],_team:Team)->[Cricketer]{varfilteredResults=[Cricketer]()foritemincricketers{ifitem.team==team{filteredResults.append(item)}}returnfilteredResults}

}

WewriteaclasscalledCricketerFilteranddefineamethodfilterByTeamtofiltertheplayerprofilesbasedontheirteam.IttakesanarrayoftypeCricketerandteamoftypeTeamasparametersandreturnsafilteredarrayoftypeCricketer.

Foreachcricketerinthegivenarray,wecheckifhisteamisthesameasthatofthegiventeamforthefilter,thenaddhimtothefilteredarray.Letusseethiscodeinaction.AddthebelowcodeafterCricketerFilterclass.

funcmain(){letdhoni=Cricketer("Dhoni",.india,.batsman)letkohli=Cricketer("Kohli",.india,.batsman)letmaxi=Cricketer("Maxwell",.australia,.allrounder)letsmith=Cricketer("Smith",.australia,.batsman)letsymo=Cricketer("Symonds",.australia,.allrounder)letbroad=Cricketer("Broad",.england,.bowler)letali=Cricketer("Ali",.pakistan,.batsman)letstokes=Cricketer("Stokes",.england,.allrounder)letcricketers=[dhoni,kohli,maxi,broad,ali,stokes,smith,symo]print("IndianCricketers")letcricketerFilter=CricketerFilter()foritemincricketerFilter.filterByTeam(cricketers,.india){print("\(item.name)belongstoIndianTeam")}}

main()

Page 22: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

OutputintheXcodeconsole:

IndianCricketersDhonibelongstoIndianTeamKohlibelongstoIndianTeam

Assume,afterafewdays,wegotanewrequirementtobeabletofilterbyroleofthecricketerandthentofilterbybothteamandroleatonce.OurCricketerFilterclasswouldlooksomethinglikethis:

classCricketerFilter{

funcfilterByRole(_cricketers:[Cricketer],_role:Role)->[Cricketer]{varfilteredResults=[Cricketer]()foritemincricketers{ifitem.role==role{filteredResults.append(item)}}returnfilteredResults}

funcfilterByTeam(_cricketers:[Cricketer],_team:Team)->[Cricketer]{varfilteredResults=[Cricketer]()foritemincricketers{ifitem.team==team{filteredResults.append(item)}}returnfilteredResults}funcfilterByRoleAndTeam(_cricketers:[Cricketer],_role:Role,_team:Team)->[Cricketer]{varfilteredResults=[Cricketer]()foritemincricketers{ifitem.role==role&&item.team==team{filteredResults.append(item)

Page 23: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

}}returnfilteredResults}

}

ThislogicisquitesimilartofilterByTeammethod,exceptwithfilterByRole,wecheckiftheplayer’sroleisthesameasthatofthegivenrole.ForfilterByRoleAndTeammethod,weuseANDstatementtocheckifthegivenconditionismet.

TheOCPstatesthatclassesshouldbeclosedformodificationandopenforextension.But,hereweareclearlybreakingthisprinciple.LetusseehowthesameusecasecanbeservedwiththehelpofOCP.

//ConditionsprotocolCondition{associatedtypeTfuncisConditionMet(_item:T)->Bool}

WebeginbydefiningaprotocolcalledCondition,whichbasicallychecksifaparticularitemsatisfiessomecriteria.WehaveafunctioncalledisConditionMet,whichtakesanitemofgenerictypeTandreturnsabooleanindicatingwhethertheitemmeetsthegivencriteria.

protocolFilter{associatedtypeTfuncfilter<Cond:Condition>(_items:[T],_cond:Cond)->[T]whereCond.T==T;}

WethendefineaprotocolnamedFilterthathasafunctioncalledfilter,whichtakesanarrayofitemsofgenerictypeTandaconditionoftypeConditionasparametersandreturnsthefilteredarray.

WenowusetheabovegenerictypeFiltertowriteconditionsforroleandteam.

Page 24: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

classRoleCondition:Condition{typealiasT=Cricketerletrole:Roleinit(_role:Role){self.role=role}funcisConditionMet(_item:Cricketer)->Bool{returnitem.role==role}}

classTeamCondition:Condition{typealiasT=Cricketerletteam:Teaminit(_team:Team){self.team=team}funcisConditionMet(_item:Cricketer)->Bool{returnitem.team==team}}

Ineachofthemethods,wewritethelogicofisConditionMetprotocolmethodtoseeiftheitemmeetsthecriteriaandreturnsaboolean.

classOCPCricketFilter:Filter{typealiasT=Cricketerfuncfilter<Cond:Condition>(_items:[Cricketer],_cond:Cond)->[T]whereCond.T==T{

Page 25: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

varfilteredItems=[Cricketer]()foriinitems{ifcond.isConditionMet(i){filteredItems.append(i)}}returnfilteredItems}}

NowwedefineabrandnewfiltercalledOCPCricketFilter,usageofwhichdoesnotviolateOCP.WetakeitemsoftypeCricketer,checkfortheconditionoftypeCondition,andreturnthefilteredarray.

Letusnowseethecodeinaction.Changethemainmethodtothefollowing:

funcmain(){letdhoni=Cricketer("Dhoni",.india,.batsman)letkohli=Cricketer("Kohli",.india,.batsman)letmaxi=Cricketer("Maxwell",.australia,.allrounder)letsmith=Cricketer("Smith",.australia,.batsman)letsymo=Cricketer("Symonds",.australia,.allrounder)letbroad=Cricketer("Broad",.england,.bowler)letali=Cricketer("Ali",.pakistan,.batsman)letstokes=Cricketer("Stokes",.england,.allrounder)letcricketers=[dhoni,kohli,maxi,broad,ali,stokes,smith,symo]

letocpFilter=OCPCricketFilter()

print("EnglandCricketers")foriteminocpFilter.filter(cricketers,TeamCondition(.england)){print("\(item.name)belongstoEnglishTeam")}}

WetakeaninstanceofOCPFilterandjustpasstheteamnameparameterto

Page 26: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

TeamCondition.

OutputintheXcodeconsole:

EnglandCricketersBroadbelongstoEnglishTeamStokesbelongstoEnglishTeam

Inasimilarway,withoutmodifyinganyexistingclasses,wecanextendtheOCPCricketFilterclasstoasmanyfiltersasweneed.NowwewillseehowwecanwriteafilterforANDcondition(roleandteamforexample):

classAndCondition<T,CondA:Condition,CondB:Condition>:ConditionwhereT==CondA.T,T==CondB.T{letfirst:CondAletsecond:CondBinit(_first:CondA,_second:CondB){self.first=firstself.second=second}funcisConditionMet(_item:T)->Bool{returnfirst.isConditionMet(item)&&second.isConditionMet(item)}}

Thisisverymuchsimilartootherfilters.Theonlychangeisthatittakestwoconditionsasargumentsforitsinitialisation.

Changethemainmethodtothebelowcode:

funcmain(){letdhoni=Cricketer("Dhoni",.india,.batsman)letkohli=Cricketer("Kohli",.india,.batsman)

Page 27: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

letmaxi=Cricketer("Maxwell",.australia,.allrounder)letsmith=Cricketer("Smith",.australia,.batsman)letsymo=Cricketer("Symonds",.australia,.allrounder)letbroad=Cricketer("Broad",.england,.bowler)letali=Cricketer("Ali",.pakistan,.batsman)letstokes=Cricketer("Stokes",.england,.allrounder)letcricketers=[dhoni,kohli,maxi,broad,ali,stokes,smith,symo]

letocpFilter=OCPCricketFilter()

print("AustralianAllrounders")foriteminocpFilter.filter(cricketers,AndCondition(TeamCondition(.australia),RoleCondition(.allrounder))){print("\(item.name)belongstoAustraliaTeamandisanAllrounder")}}

OutputintheXcodeconsole:

AustralianAllroundersMaxwellbelongstoAustraliaTeamandisanAllrounderSymondsbelongstoAustraliaTeamandisanAllrounder

Wecanwritennumberoffilterswithoutmodifyinganyexistingclasses.AllwehavetodoisextendtheFilterclass.

Page 28: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

3)SOLID-LiskovSubstitutionPrinciple(LSP)Definition:

Liskovsubstitutionprinciple,namedafterBarbaraLiskov,statesthatoneshouldalwaysbeabletosubstituteabasetypeforasubtype.LSPisawayofensuringthatinheritanceisusedcorrectly.Ifamoduleisusingabaseclass,thenthereferencetothebaseclasscanbereplacedwithaderivedclasswithoutaffectingthefunctionalityofthemodule.

Usage:

LetusunderstandLSP’susagewithasimpleexample.

importUIKitimportFoundation

protocolCricketer{funccanBat()funccanBowl()funccanField()}

WedefineaprotocolcalledCricketer,whichimplementsthreemethodsofcanBat,canBowl,andcanField.

classAllRounder:Cricketer{funccanBat(){print("Icanbat")}

Page 29: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funccanBowl(){print("Icanbowl")}funccanField(){print("Icanfield")}}

WethendefineaclasscalledAllRounder,conformingtoCricketerprotocol.Anall-rounderincricketissomeonewhocanbat,bowl,andfield.

classBatsman:Cricketer{funccanBat(){print("Icanbat")}funccanBowl(){print("Icannotbowl")}funccanField(){print("Icanfield")}}

WethendefineaclasscalledBatsman,conformingtoCricketerprotocol.ThisisaviolationofLSP,asabatsmanisacricketerbutcannotuseCricketerprotocolbecausehecannotbowl.LetusnowseehowwecanuseLSPinthisscenario:

protocolCricketer{funccanBat()funccanField()}

classBatsman:Cricketer{funccanBat(){print("Icanbat")}

Page 30: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funccanField(){print("Icanfield")}}

WechangetheCricketerprotocolandnowmaketheBatsmanclassconformtoCricketerprotocol.

classBatsmanWhoCanBowl:Cricketer{

funccanBat(){print("Icanbat")}funccanField(){print("Icanfield")}funccanBowl(){print("Icanbowl")}

}

classAllRounder:BatsmanWhoCanBowl{}

WethendefineanewclassnamedBatsmanWhoCanBowlwithsuperclassasCricketeranddefinetheextramethodofcanBowlinthisclass.

Page 31: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

4)SOLID-InterfaceSegregationPrinciple(ISP)Definition:

TheonlymottoofInterfacesegregationprincipleisthattheclientsshouldnotbeforcedtoimplementinterfacestheydon’tuse.Clientsshouldnothavethedependencyontheinterfacesthattheydonotuse.

Usage:

Letusassumewearebuildingascreendisplayformobile,tablet,anddesktopinterfacesofanappthatisusedtodisplaylivescoresofacricketmatch.

WewillseehowthiscanbeachievedwithoutusingISPandthenusingISP.

importUIKitimportFoundation

//BeforeISPprotocolMatchSummaryDisplay{funcshowLiveScore()funcshowCommentary()funcshowLiveTwitterFeed()funcshowSmartStats()}

WedefineaprotocolnamedMatchSummaryDisplay,whichhasfourmethodstoshowlivescore,commentary,twitterfeedaboutthematch,andstatisticsoftheplayers.

enumNoScreenEstate:Error

Page 32: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

{casedoesNotShowLiveTwitterFeedcasedoesNotShowSmartStats}

extensionNoScreenEstate:LocalizedError{publicvarerrorDescription:String?{switchself{case.doesNotShowLiveTwitterFeed:returnNSLocalizedString("NoScreenEstatetoshowLiveTwitterFeed",comment:"Error")case.doesNotShowSmartStats:returnNSLocalizedString("NoScreenEstatetoshowSmartStats",comment:"Error")}}}

Bydefault,wewanttoshowthelivescoreandcommentaryonalltypesofdeviceslikemobile,tablet,anddesktop.Showingtwitterfeedandstatisticsareoptional,dependingonthescreenestateavailableonthedevice.So,wedefineanenumcalledNoScreenEstatewithtwopossiblecases.Wealsowriteanextensiontoitjusttomaketheerrordescriptionsmoreclear.

classDesktopDisplay:MatchSummaryDisplay{funcshowLiveScore(){print("ShowingLiveScoreOnDesktop")}funcshowCommentary(){print("ShowingCommentaryOnDesktop")}funcshowLiveTwitterFeed(){print("ShowingLiveTwitterFeedOnDesktop")}funcshowSmartStats(){print("ShowingSmartStatsOnDesktop")

Page 33: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

}}

WestarttheinterfacedesignbydefiningaclasscalledDesktopDisplayconformingtoMatchSummaryDisplay.Adesktophasenoughscreenspaceavailable,andweshowalltheavailabledatatotheuser.

classTabletDisplay:MatchSummaryDisplay{funcshowLiveScore(){print("ShowingLiveScoreOnTablet")}funcshowCommentary(){print("ShowingCommentaryOnTablet")}funcshowLiveTwitterFeed(){print("ShowingLiveTwitterFeedOnTablet")}funcshowSmartStats(){do{leterror:Error=NoScreenEstate.doesNotShowSmartStatsprint(error.localizedDescription)throwerror}catch{}}}

WethendefineanotherclasscalledTabletDisplayconformingtoMatchSummaryDisplay.Asthescreensizeofatabletislesswhencomparedtoadesktop,wedonotshowsmartstatsonthetabletdisplay.WethrowanerrorinshowSmartStatsmethod.

classMobileDisplay:MatchSummaryDisplay{funcshowLiveScore(){print("ShowingLiveScoreOnMobile")

Page 34: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

}funcshowCommentary(){print("ShowingCommentaryOnMobile")}funcshowLiveTwitterFeed(){do{leterror:Error=NoScreenEstate.doesNotShowLiveTwitterFeedprint(error.localizedDescription)throwerror}catch{}}funcshowSmartStats(){do{leterror:Error=NoScreenEstate.doesNotShowSmartStatsprint(error.localizedDescription)throwerror}catch{}}}

WethendefineanotherclasscalledMobileDisplayconformingtoMatchSummaryDisplay.Asthescreensizeofmobileisevensmallerwhencomparedtodesktopandtablet,wedonotshowsmartstatsandtwitterfeedonmobiledisplay.WethrowanerrorinshowLiveTwitterFeedandshowSmartStatsmethods.

Asyoucansee,thisapproachviolatesISPbecauseTabletDisplayandMobileDisplayareforcedtoimplementmethodstheyarenotusing.Let’sseehowwecanuseISPinthisscenario.

//FollowingISP

Page 35: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

protocolLiveScoreDisplay{funcshowLiveScore()funcshowCommentary()}

protocolTwitterFeedDisplay{funcshowLiveTwitterFeed()}

protocolSmartStatsDisplay{funcshowSmartStats()}

HerewedefineaprotocolnamedLiveScoreDisplay,whichismandatoryforallthescreensizesofthedevices.ThenwedefinedifferentprotocolscalledTwitterFeedDisplayandSmartStatsDisplaysothatonlythedeviceswithenoughscreensizescanconformtorequiredprotocols.

classISPMobileDisplay:LiveScoreDisplay{funcshowLiveScore(){print("ShowingLiveScoreOnMobile")}funcshowCommentary(){print("ShowingCommentaryOnMobile")}}

WedefineaclasscalledISPMobileDisplay,whichconformsonlytoLiveScoreDisplay.Wedon’thavetoforcetheclasstoimplementanyunwantedmethods.

classISPTabletDisplay:LiveScoreDisplay,TwitterFeedDisplay{funcshowLiveScore(){print("ShowingLiveScoreOnTablet")}funcshowCommentary(){

Page 36: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

print("ShowingCommentaryOnTablet")}funcshowLiveTwitterFeed(){print("ShowingLiveTwitterFeedOnTablet")}}

WethendefineaclasscalledISPTabletDisplay,whichconformstoTwitterFeedDisplayalongwithLiveScoreDisplay.

Wecandefinedesktopinterfaceasfollows:

classISPDesktopDisplay:LiveScoreDisplay,TwitterFeedDisplay,SmartStatsDisplay{funcshowLiveScore(){print("ShowingLiveScoreOnDesktop")}funcshowCommentary(){print("ShowingCommentaryOnDesktop")}funcshowLiveTwitterFeed(){print("ShowingLiveTwitterFeedOnDesktop")}funcshowSmartStats(){print("ShowingSmartStatsOnDesktop")}}

Wecanobservethat,inalltheabovethreeclasses,wearenotforcinganyclasstoimplementamethodthattheydonotuse.WeachievedISPbydefiningmultipleprotocols.

Page 37: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

5)SOLID-DependencyInversionPrinciple(DIP)Definition:

Inshort,Dependencyinversionprinciplesaystodependonabstractions,notonconcretions.High-levelmodulesshouldnotdependuponlow-levelmodules.Bothshoulddependuponabstractions.

Abstractionsshouldnotdependupondetails.Detailsshoulddependuponabstractions.Bydependingonhigher-levelabstractions,wecaneasilychangeoneinstancewithanotherinstanceinordertochangethebehaviour.DIPincreasesthereusabilityandflexibilityofourcode.

Usage:

Letusassumewearedesigningasmallsystemwherewewanttolistfromthedatabaseallthewicketstakenbyabowlerinhiscricketingcareer.

importFoundationimportUIKit

enumWicketsColumn{casewicketTakenBycasewicketGivenTo}

classCricketer{varname=""init(_name:String){self.name=name

Page 38: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

}}

WedefineanenumcalledWicketsColumnwithalistoftwopossiblecases.WethendefineaclasscalledCricketerthattakestheparameterofnameoftypeStringforitsinitialisation.

protocolWicketsTallyBrowser{funcreturnAllWicketsTakenByBowler(_name:String)->[Cricketer]}

WedefineaprotocolnamedWicketsTallyBrowser,whichhasafunctiontoreturnallthewicketstakenbyagivenbowlerasanarrayoftypeCricketer.

Wewillnowdefineaclass,whichstoresrelationshipbetweenbowlersandbatsmen.

classWicketsTally:WicketsTallyBrowser{//LowLevelvarwickets=[(Cricketer,WicketsColumn,Cricketer)]()funcaddToTally(_bowler:Cricketer,_batsman:Cricketer){wickets.append((bowler,.wicketTakenBy,batsman))wickets.append((batsman,.wicketGivenTo,bowler))}funcreturnAllWicketsTakenByBowler(_name:String)->[Cricketer]{returnwickets.filter({$0.name==name&&$1==WicketsColumn.wicketTakenBy&&$2!=nil}).map({$2})}}

WedefineaclasscalledWicketsTallyconformingtoWicketsTallyBrowserprotocol.Ithasavariablecalledwickets,whichisanarrayoftupleswhereeachofthetupleshasthreeattributes:oneeachoftypeCricketer,WicketsColumn,andCricketer,inthatorder.

Page 39: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

ThenwedefineamethodcalledaddToTally,whichtakesparametersofbowlerandbatsmanoftypeCricketer.ItappendsthesametothewicketsarraybutwithdifferentrelationshipsavailablefromWicketsColumnenum.

InthedefinitionofprotocolmethodreturnAllWicketsTakenByBowler,wefilterthewicketsarraybycomparingfirstattributeoftupletothenameofthegivenbowler.

classPlayerStats{//HighLevelinit(_wicketsTally:WicketsTally){letwickets=wicketsTally.wicketsforwinwicketswherew.0.name=="BrettLee"&&w.1==.wicketTakenBy{print("BrettLeehasawicketof\(w.2.name)")}}}

WenowdefineaclasscalledPlayerStats,whereweusethelogicwritteninWicketsTallyclasstoreturnallthewicketstakenbyaparticularbowler.

Letusnowwriteamainmethodtoseethiscodeinaction.

funcmain(){letbowler=Cricketer("BrettLee")letbatsman1=Cricketer("Sachin")letbatsman2=Cricketer("Dhoni")letbatsman3=Cricketer("Dravid")letwicketsTally=WicketsTally()wicketsTally.addToTally(bowler,batsman1)wicketsTally.addToTally(bowler,batsman2)wicketsTally.addToTally(bowler,batsman3)let_=PlayerStats(wicketsTally)}

Page 40: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

OutputintheXcodeconsole:

BrettLeehasawicketofSachinBrettLeehasawicketofDhoniBrettLeehasawicketofDravid

TheissuewiththeaboveapproachisitsviolationofDIP(itstatesthatthehigh-levelmodulesshouldnotdirectlydependonlow-levelmodules),asourPlayerStatsclassdependsuponwicketsarrayofWicketsTallyclass.Itshouldbedeclaredasaprivatevariablesothatnootherclasscanmanipulatethedatadirectly.

LetusnowchangetheWicketsTallyclassthisway:

classWicketsTally:WicketsTallyBrowser{//LowLevelprivatevarwickets=[(Cricketer,WicketsColumn,Cricketer)]()funcaddToTally(_bowler:Cricketer,_batsman:Cricketer){wickets.append((bowler,.wicketTakenBy,batsman))wickets.append((batsman,.wicketGivenTo,bowler))}funcreturnAllWicketsTakenByBowler(_name:String)->[Cricketer]{returnwickets.filter({$0.name==name&&$1==WicketsColumn.wicketTakenBy&&$2!=nil}).map({$2})}}

NowchangethePlayerStatsclassto:

classPlayerStats{//HighLevelinit(_browser:WicketsTallyBrowser){forwinbrowser.returnAllWicketsTakenByBowler("BrettLee"){print("BrettLeehasawicketof\(w.name)")}}}

Page 41: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

Herewecanobservethat,insteadofdirectlydependingonwicketsarrayfromWicketsTally,PlayerStatsisdependentonabstractionfromWicketsTallyBrowser.OutputintheXcodeconsoleremainsthesamebutwearenowadheringtoDIP.

OutputintheXcodeconsole:

BrettLeehasawicketofSachinBrettLeehasawicketofDhoniBrettLeehasawicketofDravid

Page 42: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

PartTwo:Creational

Page 43: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

6)Creational-FactoryDesignPatternDefinition:

FactorydesignpatternisalsoknownasVirtualConstructor.Itisacreationaldesignpatternthatdefinesanabstractclassforcreatingobjectsinsuperclassbutallowsthesubclassestodecidewhichclasstoinstantiate.

Usage:

AssumethereisaBowlingMachinethatdeliversRedCricketBalls(usedforTestCricket)andWhiteCricketBalls(usedforLimitedOversCricket)basedonuserinput.

importUIKit

protocolCricketBall{funchitMe()}

AnyclassconformingtoCricketBallmustimplementhitMemethod.

classRedBall:CricketBall{funchitMe(){print("ThisballisgoodforTestCricket")}}

classWhiteBall:CricketBall{funchitMe(){print("ThisballisgoodforLimitedOversCricket")

Page 44: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

}}

Letusstartdefiningfactoriesnow.

protocolCricketBallFactory{

init()funcdeliverTheBall(_speed:Int)->CricketBall}

FactoriesconformingtoCricketBallFactorymustimplementdeliverTheBall.Weshouldalsogivesomeinputlikethespeedatwhichwewanttheballtobedelivered.

Now,movingoutofabstractclassescreatingobjects,westartdefiningsubclassesforobjectcreation.

classRedBallFactory{funcdeliverTheBall(_speed:Int)->CricketBall{print("ReleasingRedBallat\(speed)speed")returnRedBall()}}

classWhiteBallFactory{funcdeliverTheBall(_speed:Int)->CricketBall{print("ReleasingWhiteBallat\(speed)speed")returnWhiteBall()}}

Herewearedefiningtwofactoriestodeliverdifferentcoloursofballs.Weinputthespeedoftheballandgetared/whiteballinreturn.

It’stimewegotothemachineandgiveaninputtodelivertheballs.

classBowlingMachine{enumAvailableBall:String{

Page 45: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

caseredBall="RedBall"casewhiteBall="WhiteBall"staticletall=[redBall,whiteBall]}internalvarfactories=[AvailableBall:CricketBallFactory]()internalvarnamedFactories=[(String,CricketBallFactory)]()init(){forballinAvailableBall.all{lettype=NSClassFromString("FactoryDesignPattern.\(ball.rawValue)Factory")letfactory=(typeas!CricketBallFactory.Type).init()factories[ball]=factorynamedFactories.append((ball.rawValue,factory))}}funcsetTheBall()->CricketBall{foriin0..<namedFactories.count{lettuple=namedFactories[i]print("\(i):\(tuple.0)")}letinput=Int(readLine()!)!returnnamedFactories[input].1.deliverTheBall(120)}}

WedefineaclasscalledBowlingMachine.WehaveanenumofavailableballswithredBallandwhiteBallastheoptions.Thenwehaveanarrayofalltheavailableballs.

Wehaveaninternalvariablecalledfactories,whichisadictionarywithkeyastheAvailableDrinkandvalueasCricketBallFactory.ThenwedefineavariablecallednamedFactories,whichisalistoftupleswhereeachentryhasthenameofthefactoryandtheinstanceofthefactory.

Page 46: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

Intheinitialisermethod,weinitialisethefactory.Foreachballinavailableballs,wegetthetypefromactualclass.ThenweconstructthefactorybytakingthetypeandcastingitasaCricketBallFactoryandinitialisingit.Thenweappendeachfactorytothearrayoffactories.

Wethendefineafunctionthatasksustosettheballandreturnsacricketball.Foreachfactory,weprintouttheindexandthenameofthefactory.Thenbasedontheinputenteredbytheuser,wereturncricketBallatgivenspeed.

Let’snowdefineafunctioncalledmainandseethecodeinaction.

funcmain(){letbowlingMachine=BowlingMachine()print(bowlingMachine.namedFactories.count)letball=bowlingMachine.setTheBall()ball.hitMe()}

main()

HereweinitialisetheBowlingMachineandsettheball.ThenwecallthehitMemethodontheinstanceofeachballtheuserinputs.

OutputintheXcodeconsole:

2AvailableBalls0:RedBall1:WhiteBall

Ifwechoose0,weprint‘ReleasingRedBallat20speed’.Ifwechoose1,weprint‘ReleasingWhiteBallat20speed’.

Summary:

Whenyouareinasituationwhereaclassdoesnotknowwhatsubclasseswillberequiredtocreate,orwhenaclasswantsitssubclassestospecifytheobjectstobecreated,goforFactorydesignpattern.

Page 47: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

7)Creational-BuilderDesignPattern:

Definition:

Builderisacreationaldesignpatternthathelpsinpiecewiseconstructionofcomplexobjectsavoidingtoomanyinitialiserarguments.Itletsusproducedifferenttypesandrepresentationsofanobjectusingthesameprocessofbuilding.

Thispatternprimarilyinvolvesthreetypes:

Product-complexobjecttobecreatedBuilder-handlesthecreationofproductDirector-acceptsinputsandcoordinateswiththebuilder

Usage:

Letusassumewearecreatingacricketteamthatconsistsofacaptain,batsmen,andbowlers.WewillseehowwecanuseBuilderpatterninthiscontext.

WestartwiththeProductpartfirst.

importUIKit

//MARK:-ProductpublicstructCricketTeam{publicletcaptain:Captainpublicletbatsmen:Batsmenpublicletbowlers:Bowlers}

extensionCricketTeam:CustomStringConvertible{publicvardescription:String{return"Teamwithcaptain\(captain.rawValue)"}}

WefirstdefineCricketTeam,whichhaspropertiesforcaptain,batsmen,and

Page 48: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

bowlers.Onceateamisset,weshouldn’tbeabletochangeitscomposition.WealsomakeCricketTeamconformtoCustomStringConvertible.

publicenumCaptain:String{caseDhonicaseKohlicaseRahane}

WedeclareCaptainasenum.Eachteamcanhaveonlyonecaptain.

publicstructBatsmen:OptionSet{publicstaticlettopOrderBatsman=Batsmen(rawValue:1<<0)publicstaticletmiddleOrderBatsman=Batsmen(rawValue:1<<1)publicstaticletlowerOrderBatsman=Batsmen(rawValue:1<<2)publicletrawValue:Intpublicinit(rawValue:Int){self.rawValue=rawValue}}

publicstructBowlers:OptionSet{publicstaticletfastBowler=Bowlers(rawValue:1<<0)publicstaticletmediumPaceBowler=Bowlers(rawValue:1<<1)publicstaticletspinBowler=Bowlers(rawValue:1<<2)publicletrawValue:Intpublicinit(rawValue:Int){self.rawValue=rawValue}}

WedefineBatsmenandBowlersasOptionSet.Thisallowsustotrydifferentcombinationsofbatsmentogether,likeateamwithtwotopOrderBatsmanandonemiddleOrderBatsman.SamewithBowlerswherewecanchooseacombinationoffastBowler,mediumPaceBowler,andaspinBowlerfortheteam.

AddthefollowingcodetomakeBuilder:

Page 49: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

//MARK:-BuilderpublicclassCricketTeamBuilder{publicenumError:Swift.Error{casealreadyTaken}publicprivate(set)varcaptain:Captain=.Dhonipublicprivate(set)varbatsmen:Batsmen=[]publicprivate(set)varbowlers:Bowlers=[]privatevarsoldOutCaptains:[Captain]=[.Dhoni]publicfuncaddBatsman(_batsman:Batsmen){batsmen.insert(batsman)}publicfuncremoveBatsman(_batsman:Batsmen){batsmen.remove(batsman)}publicfuncaddBowler(_bowler:Bowlers){bowlers.insert(bowler)}publicfuncremoveBowler(_bowler:Bowlers){bowlers.remove(bowler)}

publicfuncpickCaptain(_captain:Captain)throws{guardisAvailable(captain)else{throwError.alreadyTaken}self.captain=captain}publicfuncisAvailable(_captain:Captain)->Bool{return!soldOutCaptains.contains(captain)}

Page 50: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

publicfuncmakeTeam()->CricketTeam{returnCricketTeam(captain:captain,batsmen:batsmen,bowlers:bowlers)}

}

Wedeclarepropertiesforcaptain,batsmen,andbowlers.Thesearedeclaredasvarsothatwecanchangetheteam’scompositionbasedontherequirement.Weareusingprivate(set)foreachtoensureonlyCricketTeamBuildercansetthemdirectly.

Sinceeachpropertyisdeclaredprivate,weneedtoprovidepublicmethodstochangethem.WedefinedmethodslikeaddBatsman,removeBatsman,addBowler,removeBowler,etc.,forthepurposeofbuildingtheteam.

Wehaveaninterestingthingtonotehere.Everyteambydefaultshouldhaveacaptain.AssumeyouarestartingateamwithDhoniascaptain.WhatifsomeotherteamtriestochooseDhoniascaptaintoo?WeshouldthrowsomeerrorusingthearrayofsoldOutCaptains.WechecktheavailabilityofthecaptainsviaisAvailablemethod.

WearedonewiththeBuilder.Now,let’sbuildourDirector.

//MARK:-Director/MakerpublicclassTeamOwner{publicfunccreateTeam1()throws->CricketTeam{letteamBuilder=CricketTeamBuilder()tryteamBuilder.pickCaptain(.Kohli)teamBuilder.addBatsman(.topOrderBatsman)teamBuilder.addBowler([.fastBowler,.spinBowler])returnteamBuilder.makeTeam()}

publicfunccreateTeam2()throws->CricketTeam{letteamBuilder=CricketTeamBuilder()tryteamBuilder.pickCaptain(.Dhoni)teamBuilder.addBatsman([.topOrderBatsman,.lowerOrderBatsman])teamBuilder.addBowler([.mediumPaceBowler,.spinBowler])

Page 51: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

returnteamBuilder.makeTeam()}

}

WehaveaclasscalledTeamOwner,whobuildstheirteamsfromtheavailableoptions.EachteamisbuilttakinganinstanceofCricketTeamBuilder,pickingupacaptainandarraysofdifferenttypesofbatsmenandbowlers.

Now,let’sdefineafunctioncalledmaintoseethecodeinaction.

funcmain(){letowner=TeamOwner()ifletteam=try?owner.createTeam1(){print("Hello!"+team.description)}}

main()

WetrytousemethodcreateTeam1withcaptainasKohli.

OutputintheXcodeconsole:

Hello!TeamwithcaptainKohli

Now,changethemain()tothefollowing:

funcmain(){letowner=TeamOwner()ifletteam=try?owner.createTeam1(){print("Hello!"+team.description)}ifletteam=try?owner.createTeam2(){print("Hello!"+team.description)}else{print("Sorry!Captainalreadytaken")

Page 52: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

}}

main()

AfterTeam1,wearetryingtocreateaTeam2withthehelpofcreateTeam2()withDhoniascaptain.ButDhoniisalreadytakenandwethrowtheerror.

OutputintheXcodeconsole:

Hello!TeamwithcaptainKohliSorry!Captainalreadytaken

Summary:

Ifyouaretryingtousethesamecodeforbuildingdifferentproductstoisolatethecomplexconstructioncodefrombusinesslogic,Builderdesignpatternfitsthebest.

Also,becarefulwhenyourproductdoesnotrequiremultipleparametersforinitialisationorconstruction.Inthisinstanceit’sadvisedtostayawayfromBuilderpattern.

Page 53: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

8)Creational-PrototypeDesignPatternDefinition:

Prototypeisacreationaldesignpatternusedtoproducenewobjectsthathaveveryfewdifferences.Aprototypeisbasicallyatemplateofanyobjectbeforetheactualobjectisconstructed.ThePrototypepatterndelegatesacloningprocesstoobjectsthemselves.

Usage:

Letusconsiderasimpleusecasewherewewanttocreatetheprofileoftwocricketers,includingtheirnameandacustomprofilethatincludesrunsscoredandwicketstaken.

importUIKit

classProfile:CustomStringConvertible{varrunsScored:IntvarwicketsTaken:Intinit(_runsScored:Int,_wicketsTaken:Int){self.runsScored=runsScoredself.wicketsTaken=wicketsTaken}vardescription:String{return"\(runsScored)RunsScored&\(wicketsTaken)WicketsTaken"}}

Page 54: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

First,wecreateaProfileclassthatconformstoCustomStringConvertible.Ithastwoproperties,runsScoredandwicketsTakenoftypeint.Ittakesthesameparametersduringitsinitialisation.

ThenwedefineaCricketerclassthatconformstoCustomStringConvertible.Ithastwoproperties,nameoftypeStringandprofileofcustomtypeProfile,whichwejustcreated.

classCricketer:CustomStringConvertible{varname:Stringvarprofile:Profileinit(_name:String,_profile:Profile){self.name=nameself.profile=profile}vardescription:String{return"\(name):Profile:\(profile)"}}

Letusnowwriteafunctioncalledmaintoseethethingsinaction.

funcmain(){letprofile=Profile(1200,123)letbhuvi=Cricketer("Bhuvi",profile)print(bhuvi.description)}

main()

IntheXcodeconsoleitprints:

Bhuvi:Profile:1200RunsScored&123WicketsTaken

Nowweneedtotalkaboutcopyingtheobjects.

Justbeforeprintstatementinthemainfunction,addthefollowinglines:

Page 55: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

varishant=bhuviishant.name="Ishant"print(ishant.description)

IntheXcodeconsoleitprints:

Ishant:Profile:1200RunsScored&123WicketsTakenIshant:Profile:1200RunsScored&123WicketsTaken

Thisisbecauseweareonlycopyingthereferences.

Nowaddthislinejustbeforeprintingishant’sdescription:

ishant.profile.runsScored=600

IntheXcodeconsoleitprints:

Ishant:Profile:600RunsScored&123WicketsTakenIshant:Profile:600RunsScored&123WicketsTaken

Nowweneedtomakesurebhuviandishantactuallyrefertodifferentobjects.

Here,weusetheconceptofDeepCopy.Whenwedeepcopyobjects,thesystemwillcopyreferences,andeachcopiedreferencewillbepointingtoitsowncopiedmemoryobject.LetusnowseehowtoimplementDeepCopyinterfaceforourusecase.

protocolDeepCopy{funccreateDeepCopy()->Self}

First,wecreateaDeepCopyprotocolthatdefinesafunctioncalledcreateDeepCopyreturningself.

ThenmaketheclassesProfileandCricketerconformtoDeepCopyprotocol.Classesnowlooklikethis:

classProfile:CustomStringConvertible,DeepCopy{

Page 56: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

varrunsScored:IntvarwicketsTaken:Intinit(_runsScored:Int,_wicketsTaken:Int){self.runsScored=runsScoredself.wicketsTaken=wicketsTaken}vardescription:String{return"\(runsScored)RunsScored&\(wicketsTaken)WicketsTaken"}funccreateDeepCopy()->Self{returndeepCopyImplementation()}privatefuncdeepCopyImplementation<T>()->T{returnProfile(runsScored,wicketsTaken)as!T}}

WehaveaprivatemethodcalleddeepCopyImplementation,whichisgenericandabletofigureoutthetypecorrectly.Ithasatypeparameter‘T’,whichisactuallygoingtobeinferred(wedon’tprovidethistypeparameteranywhere)andareturntypeof‘T’.WereturnaProfileobjectandforcecastittoT.

Cricketerclassnowlookslikethis:

classCricketer:CustomStringConvertible,DeepCopy{varname:Stringvarprofile:Profileinit(_name:String,_profile:Profile){self.name=nameself.profile=profile}vardescription:String{return"\(name):Profile:\(profile)"

Page 57: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

}funccreateDeepCopy()->Self{returndeepCopyImplementation()}privatefuncdeepCopyImplementation<T>()->T{returnCricketer(name,profile)as!T}}

Letusdefineourmainmethodasbelowandseetheresults:

funcmain(){letprofile=Profile(1200,123)letbhuvi=Cricketer("Bhuvi",profile)letishant=bhuvi.createDeepCopy()ishant.name="Ishant"ishant.profile=bhuvi.profile.createDeepCopy()ishant.profile.wicketsTaken=140print(bhuvi.description)print(ishant.description)}

main()

OutputintheXcodeconsole:

Bhuvi:Profile:1200RunsScored&123WicketsTakenIshant:Profile:1200RunsScored&140WicketsTaken

Wecanseethatbhuviandishantaretwodifferentobjectsnow,andthisishowDeepCopyisimplemented.

Summary:

Whenyouareinasituationtocloneobjectswithoutcouplingtotheirconcreteclasses,youcanoptforPrototypedesignpattern,whichalsohelpsinreducing

Page 58: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

repetitiveinitialisationcode.

Page 59: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

9)Creational-SingletonDesignPatternWhendiscussingwhichpatternstodrop,wefoundthatwestilllovethemall(Notreally-IaminfavourofdroppingSingleton.Itsusageisalmostalwaysadesignsmell)-ErichGamma(oneoftheGangFour)

Adesignpatterneveryonelovestohate.Isitbecauseitisactuallybadorisitbecauseofitsabusebythedevelopers?Let’ssee.

Definition:

Singletonisacreationaldesignpatternthatprovidesuswithoneofthebestwaystocreateanobject.Thispatternensuresaclasshasonlyoneinstanceandprovidesaglobalaccesstoitsothattheobjectcanbeusedbyalltheotherclasses.

Usage:

LetustakethecaseofanAPIthatreturnssomeJSONresponse,whichwhenparsedlookslikethis:

["Sachin":1,"Sehwag":2,"Dravid":3,"Kohli":4,"Yuvraj":5,"Dhoni":6,"Jadeja":7,"Ashwin":8,"Zaheer":9,"Bhuvi":10,"Bumrah":11]

Thisdatastructureisanarraywhereeachobjectisakey-valuepair.KeyrepresentsthenameofIndianCricketerandValuerepresentsthepositionatwhichthecricketerbats.

WewouldneedonlyoneinstanceoftheSingletonDatabaseclassinordertosavethisdatatoourdatabase.Thereisnopointininitialisingdatabaseclassmorethanonce,asitwouldjustwastememory.Ourcodelookslikethis:

Page 60: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

importUIKitclassSingletonDatabase{vardataSource=["Sachin":1,"Sehwag":2,"Dravid":3,"Kohli":4,"Yuvraj":5,"Dhoni":6,"Jadeja":7,"Ashwin":8,"Zaheer":9,"Bhuvi":10,"Bumrah":11]

varcricketers=[String:Int]()

staticletinstance=SingletonDatabase()staticvarinstanceCount=0

privateinit(){print("Initialisingthesingleton")type(of:self).instanceCount+=1fordataElementindataSource{cricketers[dataElement.key]=dataElement.value}}

}

Wefirstmakeaprivateinitialiserthatdoesnottakeanyarguments.Andthat’sthesimplestwaytocreateonobject.Asitisprivate,noonecanmakeanotherinstanceoftheclass.

ButhowdoweletsomeoneaccesstheSingletonDatabase?That’swheretheSingletonpatterncomesintoplay.

WeinitialiseastaticvariablewiththeonlyinstanceofSingletonDatabaseclass.Makingitstaticrestrictstheabilitytocreatemultipleinstancesoftheclass.

NowweaddthedatacomingfromtheAPIcalltoourarrayofcricketers.That’sit!Wehaveourdatabaseready.

Now,howdoessomeonehaveaccesstothisdatabase?Assumewewanttoknowthepositionatwhichacricketerbats.Wewriteafunctionforthatjustaftertheprivateinit()methodinSingletonDatabaseclass.

Page 61: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcgetRunsScoredByCricketer(name:String)->Int{ifletposition=cricketers[name]{print("\(name)batsatnumber\(position)forIndianCrikcetTeam")returncricketers[name]!}

print("Cricketerwithname\(name)notfound")return0}

Thismethodisstraightforward.Ittakesthenameofthecricketerasanargumentandreturnshispositionintheline-up.

Inorderforustoaccessthisclassatsomepointinourcode,wewriteitthisway:

funcmain(){letsingleton=SingletonDatabase.instancesingleton.getRunsScoredByCricketer(name:"Sachin")}

Verysimpleandshort.Wecreateavariablenamedsingleton,whichhelpsusinaccessingallthefunctionsinourSingletonDatabaseclass.

Nowrunthemain()method.

main()

OutputintheXcodeconsole:

InitialisingthesingletonSachinbatsatnumber1forIndianCricketTeam

Changethenameparameterto“Sach”andtheoutputis:

InitialisingthesingletonCricketerwithnameSachnotfound

WehavenotyetdiscussedthevariablenamedinstanceCountinourprivateinit()

Page 62: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

method.WecanusethisvariabletoshowthatthereisonlyoneinstanceoftheSingletonDatabaseclass.

Changethemainmethodthisway:

funcmain(){letsingleton1=SingletonDatabase.instanceprint(SingletonDatabase.instanceCount)letsingleton2=SingletonDatabase.instanceprint(SingletonDatabase.instanceCount)

}

OutputintheXcodeconsole:

Initialisingthesingleton11

Instancecountremains1eventhoughweinitialisedtheclassmorethanonce.

Addingthecodesnippetforanotherself-explanatoryexamplehere,whichwouldenhanceyourunderstanding:

importUIKit

classPlayerRating:CustomStringConvertible{privatestaticvar_nameOfThePlayer=""privatestaticvar_ratingForThePlayer=0

varnameOfThePlayer:String{get{returntype(of:self)._nameOfThePlayer}set(value){type(of:self)._nameOfThePlayer=value}}

varratingForThePlayer:Int{get{returntype(of:self)._ratingForThePlayer}set(value){type(of:self)._ratingForThePlayer=value}

Page 63: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

}

vardescription:String{return"\(nameOfThePlayer)hasgotaratingof\(ratingForThePlayer)"}}

funcmain(){letplayerRating1=PlayerRating()playerRating1.nameOfThePlayer="Dhoni"playerRating1.ratingForThePlayer=8

letplayerRating2=PlayerRating()playerRating2.ratingForThePlayer=7

print(playerRating1)print(playerRating2)}main()

OutputintheXcodeconsole:

Dhonihasgotaratingof7Dhonihasgotaratingof7

Summary:

WeshoulduseSingletonpatternonlywhenwehaveascenarioforcingustouseasingleinstanceofanobjectatmultipleplaces.

Page 64: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

PartThree:Structural

Page 65: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

10)Structural-AdapterDesignPatternDefinition:

Adapterisastructuraldesignpatternthatconvertstheinterfaceofaclassintoanotherinterfaceclientsexpect.Thisallowsclasseswithincompatibleinterfacestocollaborate.

Usage:

SupposeyouhaveaTestBatsmanclasswithfieldWell()andmakeRuns()methods.AndalsoaT20BatsmanclasswithbatAggressively()method.

Let’sassumethatyouareshortonT20BatsmanobjectsandyouwouldliketouseTestBatsmanobjectsintheirplace.TestBatsmenhavesomesimilarfunctionalitybutimplementadifferentinterface(theycanbatbutcannotbatinthewayneededforaT20match),sowecan’tusethemdirectly.

WewillusetheAdapterpattern.HereourclientwouldbeT20BatsmanandadapteewouldbeTestBatsman.

Letusnowwritecode:

importUIKit

protocolTestBatsman{funcmakeRuns()funcfieldWell()}

AsimpleprotocolnamedTestBatsmandefiningtwomethods,makeRunsand

Page 66: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

fieldWell.

classBatsman1:TestBatsman{funcmakeRuns(){print("IcanbatwellbutonlyatStrikeRateof80")}funcfieldWell(){print("Icanfieldwell")}}

WedefineaBatsman1classconformingtoTestBatsmanprotocol.Thistypeofbatsmancanmakerunsatastrikerateof80.

protocolT20Batsman{funcbatAggressively()}

WehaveonemoreprotocolnamedT20Batsman,whichdefinesbatAggressivelymethod.

classBatsman2:T20Batsman{funcbatAggressively(){print("IneedtobatwellataStrikeRateofmorethan130")}}

WedefineaBatsman2classconformingtoT20Batsmanprotocol.Thistypeofbatsmancanmakerunsatastrikerateof130.

Nowconsideringoursituation,weneedtomakeanadapterinsuchawaythatTestBatsmancanfittobeaT20Batsman.

classTestBatsmanAdapter:T20Batsman{lettestBatsman:TestBatsmaninit(_testBatsman:TestBatsman){self.testBatsman=testBatsman}

Page 67: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcbatAggressively(){testBatsman.makeRuns()}}

WewriteaclassnamedTestBatsmanAdapter,whosesuperclassisT20Batsman.IthasapropertyoftypeTestBatsmanandittakesanobjectoftypeTestBatsmanforitsinitialisation.ItisthisobjectwhichwemakeadaptabletobatAggressivelymethodbycallingmakeRunsmethod.

OutputintheXcodeconsole:

TestBatsmanIcanfieldwellIcanbatwellbutonlyatStrikeRateof80T20BatsmanIneedtobatwellataStrikeRateofmorethan130TestBatsmanAdapterIcanbatwellbutonlyatStrikeRateof80

Summary:

Whenyouareinasituationwhereyouhaveanobjectthatshouldbeabletodothesametaskbutinlotsofdifferentways,andyoudonotwanttoexposethealgorithm'simplementationdetailstootherclasses,optforAdapterdesignpattern.

Page 68: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

11)Structural-BridgeDesignPatternDefinition:Bridgeisastructuraldesignpatternthatletsusconnectcomponentstogetherthroughabstraction.Itenablestheseparationofimplementationhierarchyfrominterfacehierarchyandimprovestheextensibility.Usage:LetussupposethatwehaveaprotocolnamedBatsman,whosemainfunctionistomakerunsforhisteam.

importFoundationimportUIKit

protocolBatsman{funcmakeRuns(_numberOfBalls:Int)}

makeRunstakesaparameternamednumberOfBallsoftypeInt.

LetusnowdefinethreedifferentclassesofbatsmenconformingtoBatsmanprotocol.

classTestBatsman:Batsman{funcmakeRuns(_numberOfBalls:Int){print("IamaTestBatsmanandIscore\(0.6*Double(numberOfBalls))runsin\(numberOfBalls)balls")}}

Page 69: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

classODIBatsman:Batsman{funcmakeRuns(_numberOfBalls:Int){print("IamaODIBatsmanandIscore\(1*Double(numberOfBalls))runsin\(numberOfBalls)balls")}}

classT20IBatsman:Batsman{funcmakeRuns(_numberOfBalls:Int){print("IamaT20BatsmanandIscore\(1.4*Double(numberOfBalls))runsin\(numberOfBalls)balls")}}

Wehavethreetypesofbatsmenwiththeonlydifferencebetweenthembeingthenumberofrunstheyscoreinagivennumberofballs.LetusnowdefineaprotocolPlayer,whosemainfunctionistoplay.

protocolPlayer{funcplay()}

WenowdefineaCricketerclassconformingtoPlayerprotocol.

classCricketer:Player{varnumberOfBalls:Intvarbatsman:Batsmaninit(_batsman:Batsman,_numberOfBalls:Int){self.batsman=batsmanself.numberOfBalls=numberOfBalls}funcplay(){

Page 70: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

batsman.makeRuns(numberOfBalls)}}

Cricketerclasstakestwoparametersduringitsinitialisation,oneoftypeBatsmanandtheotheroftypeInt.ThisiswherewearebridgingbetweenBatsmanclassandPlayerclassbycallingmakeRunsmethodofbatsmanintheplaymethod.

Letusnowdefineourmainfunctionandseehowthisdesignpatternworks.

funcmain(){lettestBatsman=TestBatsman()letodiBatsman=ODIBatsman()lett20Batsman=T20IBatsman()letcricketer1=Cricketer(testBatsman,20)letcricketer2=Cricketer(odiBatsman,20)letcricketer3=Cricketer(t20Batsman,20)cricketer1.play()cricketer2.play()cricketer3.play()}

main()OutputintheXcodeconsole:

IamaTestBatsmanandIscore12.0runsin20ballsIamaODIBatsmanandIscore20.0runsin20ballsIamaT20BatsmanandIscore28.0runsin20balls

Summary:

Whenyouareinasituationwhereyouhavetochangetheimplementationobjectinsidetheabstraction,andwhenyouneedtoextendaclassinseveral

Page 71: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

independentdimensions,Bridgedesignpatternservesthebest.

Page 72: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

12)Structural-CompositeDesignPatternDefinition:

Compositeisastructuraldesignpatternthatletsuscomposeobjectsintotreestructuresandallowsclientstoworkwiththesestructuresasiftheywereindividualobjects.Compositionletsusmakecompoundobjects.

Usage:

Assumewearebuildingatreestructureofacricketteamwhereeachentitycontainsname,role,andgradeofcontractasattributes.Let’sseehowwecanuseCompositedesignpatterntobuildsuchasystem.

importUIKitimportFoundation

classCricketTeamMember:CustomStringConvertible{varname:Stringvarrole:Stringvargrade:StringvarteamMembers:[CricketTeamMember]init(name:String,role:String,grade:String){self.name=nameself.role=roleself.grade=gradeself.teamMembers=[CricketTeamMember]()}

Page 73: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcaddMember(member:CricketTeamMember){teamMembers.append(member)}funcremoveMember(member:CricketTeamMember){teamMembers.append(member)}funcgetListOfTeamMembers()->[CricketTeamMember]{returnteamMembers}vardescription:String{letdemo="\(name)\(role)\(grade)"returndemo}}

Let’sstartwithdefiningaclasscalledCricketTeamMemberconformingtoCustomStringConvertible.IthasfourpropertieslikenameoftypeString,roleoftypeString,gradeoftypeString,andanarrayofteamMembersoftypeCricketTeamMember.Ittakesthreeparametersforitsinitialisation:name,role,andgradeoftypeString.

WedefineafunctioncalledaddMember,whichtakesaCricketTeamMemberobjectasparameterandappendsittotheteamMembersarray.

WehaveafunctionnamedremoveMember,whichtakesaCricketTeamMemberobjectasparameterandremovesitfromteamMembersarray.

WehaveanotherfunctioncalledgetListOfTeamMembers,whichreturnslistofteammembers.

LetusnowdefinemainfunctionandseehowtheCompositepatterncanbeusedtodefineatreestructure.

funcmain(){

Page 74: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

//1

letheadCoach=CricketTeamMember(name:"HeadCoach",role:"HeadCoach",grade:"A")letcaptain=CricketTeamMember(name:"TeamCaptain",role:"Captain",grade:"B")letbowlingCoach=CricketTeamMember(name:"BowlingCoach",role:"Coach",grade:"B")letbattingCoach=CricketTeamMember(name:"BattingCoach",role:"Coach",grade:"B")letfieldingCoach=CricketTeamMember(name:"FieldingCoach",role:"Coach",grade:"B")letasstBowlingCoach=CricketTeamMember(name:"ABoC1",role:"AsstCoach",grade:"C")letasstBattingCoach=CricketTeamMember(name:"ABaC1",role:"AsstCoach",grade:"C")letasstFieldingCoach=CricketTeamMember(name:"ABfC1",role:"AsstCoach",grade:"C")letteamMember1=CricketTeamMember(name:"TM1",role:"Player",grade:"B")letteamMember2=CricketTeamMember(name:"TM2",role:"Player",grade:"B")//2

headCoach.addMember(member:captain)headCoach.addMember(member:bowlingCoach)headCoach.addMember(member:battingCoach)headCoach.addMember(member:fieldingCoach)captain.addMember(member:teamMember1)captain.addMember(member:teamMember2)bowlingCoach.addMember(member:asstBowlingCoach)battingCoach.addMember(member:asstBattingCoach)fieldingCoach.addMember(member:asstFieldingCoach)

//3

Page 75: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

print(headCoach.description)formemberinheadCoach.getListOfTeamMembers(){print(member.description)formemberinmember.getListOfTeamMembers(){print(member.description)}}}

main()

Let’sreadthismethodstep-by-stepnow.

1. 1) HerewedefinedifferentteammembersusingtheinstanceofCricketTeamMember.WecanseedifferentroleslikeHeadCoach,TeamCaptain,BowlingCoach,etc.

1. 2) Wethenstartformingtreesbyaddingallthecaptainsandcoachesunderheadcoach,addingteammembersunderteamcaptain,etc.

1. 3) Herewestartprintingthetrees.InitiallyweprintthedescriptionofHeadCoachandthenweloopthroughalltheteammembersaddedunderhimandprinttheirdescriptionstoo.

OutputintheXcodeconsole:

HeadCoachHeadCoachATeamCaptainCaptainBTM1PlayerBTM2PlayerBBowlingCoachCoachBABoC1AsstCoachCBattingCoachCoachB

Page 76: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

ABaC1AsstCoachCFieldingCoachCoachBABfC1AsstCoachC

Summary:

Whenyouareinasituationtosimplifythecodeattheclient’sendthathastointeractwithacomplextreestructure,thengoforCompositedesignpattern.Inotherwords,itshouldbeusedwhenclientsneedtoignorethedifferencebetweencompositionsofobjectsandindividualobjects.

Page 77: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

13)Structural-DecoratorDesignPatternDefinition:

Decoratorisastructuraldesignpatternthatletsusaddnewbehaviourtotheobjectswithoutalteringtheclassitself.Ithelpsusinkeepingthenewfunctionalitiesseparatewithouthavingtorewriteexistingcode.

Usage:

AssumewearecheckingifaplayerisfitforplayingT20gameofcricketasabowlerorbatsmanorbothornone,basedonhisbattingandbowlingstatistics.LetusseehowDecoratordesignpatterncanhelpushere.

importUIKitimportFoundation

classT20Batsman{varstrikeRate:Int=0funcmakeRuns()->String{return(strikeRate>130)?"FitforT20TeamasBatsman":"TooslowBatsmanforT20Team"}}

WewriteaclasscalledT20BatsmanwithapropertycalledstrikeRateoftypeInt.IthasafunctiondefinedmakeRuns,whichtellsusifthebatsmanisfitforT20teambasedonhisstrikeRate.Ifthestrikerateismorethan130,heisfitasT20

Page 78: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

batsman,otherwiseheistooslowforthegame.

classT20Bowler{vareconomyRate:Float=0funcbowlEconomically()->String{return(economyRate<8.0)?"FitforT20TeamasBowler":"TooexpensiveasaBowler"}}

WethendefineaclasscalledT20BowlerwithapropertycalledeconomyRateoftypeFloat.IthasafunctiondefinedcalledbowlEconomically,whichtellsusifthebowlerisfitforT20teambasedonhiseconomyRate.Iftheeconomyrateislessthan8.0,heisfitasT20bowler,otherwiseheistooexpensiveasabowlerforthegame.

classT20AllRounder:CustomStringConvertible{privatevar_strikeRate:Int=0privatevar_economyRate:Float=0privatelett20Batsman=T20Batsman()privatelett20Bowler=T20Bowler()funcmakeRuns()->String{returnt20Batsman.makeRuns()}funcbowlEconomically()->String{returnt20Bowler.bowlEconomically()}varstrikeRate:Int{get{return_strikeRate}set(value){t20Batsman.strikeRate=value

Page 79: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

_strikeRate=value}}vareconomyRate:Float{get{return_economyRate}set(value){t20Bowler.economyRate=value_economyRate=value}}vardescription:String{ift20Batsman.strikeRate>130&&t20Bowler.economyRate<8{return"FitasT20AllRounder"}else{varbuffer=""buffer+=t20Batsman.makeRuns()buffer+="&"+t20Bowler.bowlEconomically()returnbuffer}}}

WenowdefineaclassforT20AllRounderconformingtoCustomStringConvertible.Allrounderissomeoneincricketwhocanbatandbowlreasonablywell.Ithasfourprivatevariables,strikeRateandeconomyRateoftypeIntandFloat,alongwithtwomorevariablesoftypeT20BatsmanandT20Bowler.

Thisallroundershouldbeabletomakerunsandbowlwell.Ithastwofunctionsdefined:

1. 1) makeRuns:HereweusetheinstanceofT20BatsmanvariabletocallthemakeRunsmethodandseeifheisfitasT20Batsmanbasedondefinedcriteriaforstrikerate.

Page 80: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

1. 2) bowlEconomically:HereweusetheinstanceofT20BowlervariabletocallthebowlEconomicallymethodandseeifheisfitasT20Bowlerbasedondefinedcriteriaforeconomyrate.

Inthefuture,ifwewanttochangetheconditionsforbatsmenorbowlerorboth,wedonothavetodisturbthecodewrittenforallrounderclass.JustchangingthecodeinT20BatsmanandT20Bowlerclasseswillbeenough.

Letusnowwriteamainfunctiontoseethecodeinaction.

funcmain(){lett20AllRounder=T20AllRounder()t20AllRounder.strikeRate=120t20AllRounder.economyRate=7print(t20AllRounder.description)

}

main()

WetakeaninstanceofT20AllRounderclassandfeedinthestrikeRateandeconomyRateandseeifacertainplayerisfitornot.

OutputintheXcodeconsole:

TooslowBatsmanforT20Team&FitforT20TeamasBowler

KeepchangingtheinputsforstrikeRateandeconomyRateandseeiftheplayerisfitforT20gameofcricket.

t20AllRounder.strikeRate=150t20AllRounder.economyRate=7

Prints:FitasT20AllRounder

Page 81: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

t20AllRounder.strikeRate=150t20AllRounder.economyRate=9

Prints:FitforT20TeamasBatsman&TooexpensiveasaBowler

t20AllRounder.strikeRate=120t20AllRounder.economyRate=9

Prints:TooslowBatsmanforT20Team&TooexpensiveasaBowler

Summary:

Ifyouareinasituationwhereyouarelookingforsomethingmoreflexiblethanclassinheritanceandneedtoedit/updatebehavioursatruntime,thenDecoratordesignpatternservesyoubetter.

Page 82: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

14)Structural-FacadeDesignPatternDefinition:

Facadeisastructuraldesignpatternthatletsusexposeseveralpatternsthroughasingle,easy-to-useinterface.Facadedefinesahigher-levelinterfacethatmakesthesubsystemeasiertousebywrappingacomplicatedsubsystemwithasimplerinterface.

Usage:

Assumewearebuildinganimaginaryplayerauctionsystemforaprivatecricketleague.Anyteamwithanidandanamecanbuyplayerswhohaveanid,roleintheteam,andaprice.Let’swritesomecodeforthis:

importUIKitimportFoundation

//TeamrepresentsanobjectthatcanbuyaplayerpublicstructTeam{publicletteamId:StringpublicvarteamName:String}

publicstructPlayer{publicletplayerId:StringpublicvarprimaryRole:Stringpublicvarprice:Double}

Page 83: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

WedefineTeamstructthatholdsthepropertiesofteamIdandteamNameasString.ThenthereisanotherstructforPlayerthatholdsplayerId,primaryRoleasStringandpriceasDouble.

//AnySwifttypethatconformstheHashableprotocolmustalsoconformtheEquatableprotocol.BecauseHashableprotocolisinheritedfromEquatableprotocol.

extensionTeam:Hashable{publicvarhashValue:Int{returnteamId.hashValue}

publicstaticfunc==(lhs:Team,rhs:Team)->Bool{returnlhs.teamId==rhs.teamId}

}

extensionPlayer:Hashable{publicvarhashValue:Int{returnplayerId.hashValue}publicstaticfunc==(lhs:Player,rhs:Player)->Bool{returnlhs.playerId==rhs.playerId}}

Wewriteacoupleofextensions,oneforTeamandoneforPlayer,eachconformingtoHashableprotocol.Whenweconformtoahashableprotocol,wemusthaveahashValueproperty.

HashableisatypethathashashValueintheformofanintegerthatcanbecomparedacrossdifferenttypes.WegetthehashValueasteamId.hashValue.

AppledefinesEquatableasatypethatcanbecomparedforvalueequality,which

Page 84: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

ispartoftheworkingdefinitionforahashableprotocol.

WethenusemandatorymethodrelatedtoHashableprotocolthatcomparesthetypeandcheckstoseeiftheyareequal.

publicclassAvailablePlayersList{publicvaravailablePlayers:[Player:Int]=[:]publicinit(availablePlayers:[Player:Int]){self.availablePlayers=availablePlayers}}

publicclassSoldPlayersList{publicvarsoldPlayers:[Team:[Player]]=[:]}

WedefineaclasscalledAvailablePlayersList.IthasavariablenamedavailablePlayersoftypeDictionary.

ThenwehaveanotherclasscalledSoldPlayerList,whichhasavariablenamedsoldPlayersthatbasicallymaintainsalistofplayersboughtbyacertainteam.

Nowwedefineourfacadewiththehelpoftheclassesdefinedabove!

publicclassAuctionFacade{publicletavailablePlayersList:AvailablePlayersListpublicletsoldPlayersList:SoldPlayersListpublicinit(availablePlayersList:AvailablePlayersList,soldPlayersList:SoldPlayersList){self.availablePlayersList=availablePlayersListself.soldPlayersList=soldPlayersList}publicfuncbuyAPlayer(forplayer:Player,byteam:Team){

Page 85: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

print("Readytobuy\(player.primaryRole)withid'\(player.playerId)'-'\(team.teamName)'")letcount=availablePlayersList.availablePlayers[player,default:0]guardcount>0else{print("'\(player.primaryRole)'issoldout")return}availablePlayersList.availablePlayers[player]=count-1varsoldOuts=soldPlayersList.soldPlayers[team,default:[]]soldOuts.append(player)soldPlayersList.soldPlayers[team]=soldOutsprint("\(player.primaryRole)with\(player.playerId)"+"boughtby'\(team.teamName)'")}}

AuctionFacadetakestwoparametersduringitsinitialisation,oneoftypeAvailablePlayersListandoneoftypeSoldPlayerList.WethendefineapublicmethodbuyAplayer.

Whenaplayerisbought,thecountforthattypeofplayerisreducedbyoneinavailablePlayerList.ThesameplayerisappendedtothelistofsoldPlayersList.

Let’snowwriteamainfunctiontoseeourfacadeinaction.

funcmain(){letbowler1=Player(playerId:"12345",primaryRole:"Bowler",price:123)letbatsman1=Player(playerId:"12365",primaryRole:"Batsman",price:152)letavailablePlayerList=AvailablePlayersList(availablePlayers:[bowler1:3,batsman1:45])letauctionFacade=AuctionFacade(availablePlayersList:availablePlayerList,

Page 86: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

soldPlayersList:SoldPlayersList())letteam1=Team(teamId:"XYZ-123",teamName:"Sydney")auctionFacade.buyAPlayer(for:bowler1,by:team1)}

main()

Wedefinebowler1andbatsman1asPlayertypeobjects.WetheninitialiseAvailablePlayerListwith3bowler1typePlayersand45batsman1typePlayers.

WethentakeaninstanceofAuctionFacadeandprovideavailablePlayerListandinstanceofSoldPlayerListasparameters.

OutputintheXcodeconsole:

ReadytobuyBowlerwithid'12345'-'Sydney'Bowlerwith12345boughtby'Sydney'

Summary:

Whenyouwanttoprovideasimpleinterfacetoacomplexsubsystemandhaveasingleinterfacefortraversingdifferentdatastructures,Facadedesignpatternsworksthebest.

Page 87: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

15)Structural-FlyWeightDesignPatternDefinition:

FlyWeightisastructuraldesignpatternthathelpsinavoidingredundancywhilestoringdata.IthelpsfitmoreobjectsintheavailableamountofRAMbyreusingalreadyexistingsimilarkindsofobjectsbystoringthemandcreatinganewobjectwhennomatchingobjectisfound.

Assumeyouarestoringfirstandlastnamesinmemory.Whentherearemanypeoplewithidenticalfirstandlastnames,thereisnopointinstoringthemagainandagainasanewentity.InsteadweusesomethinglikeFlyWeightdesignpatterntosavethestoragespace.

Usage:

Letusconsiderasituationwherewearestoringplayerprofileswhereeachentityconsistsofplayer’snameoftypeStringandtheteamsheplayedforoftypeStringarrayasattributes.

WewritethecodewithoutusingFlyWeightdesignpatternandcheckthememoryoccupied.

importUIKitimportFoundation

classPlayerProfile{varfullName:StringvarteamsPlayedFor:[String]init(_fullName:String,_teamsPlayedFor:[String]){

Page 88: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

self.fullName=fullNameself.teamsPlayedFor=teamsPlayedFor}varcharCount:Int{varcount=0forteaminteamsPlayedFor{count+=team.utf8.count}count+=fullName.utf8.countreturncount}}

WedefineaclasscalledPlayerProfile,whichtakesfullNameoftypeStringandteamsPlayedForoftypeStringarrayasparametersduringitsinitialisation.

WethendefineavariablecalledcharCount,whichisanindicatorofthememoryoccupied.Letuswriteourmainfunctionandcheckthecharactercount.

funcmain(){letdhoni=PlayerProfile("MahendraDhoni",["India,Chennai"])letkohli=PlayerProfile("ViratKohli",["India,Bangalore"])letyuvi=PlayerProfile("YuvrajSingh",["India,Punjab"])print("Totalnumberofcharsused:",dhoni.charCount+kohli.charCount+yuvi.charCount)}

main()

WedefineafewinstancesofPlayerProfilebypassingtheplayers’namesandtheirteamsasparameters.ThenweusethecharCountpropertyonalltheinstancesandprintittotheconsole.

OutputintheXcodeconsole:

Page 89: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

Totalnumberofcharsused:82

LetusnowuseFlyWeightdesignpatternforthesameusecase.

classPlayerProfileOptimised{staticvarstringsArray=[String]()privatevargenericNames=[Int]()init(_fullName:String,_teamsPlayedFor:[String]){funcgetOrAdd(_s:String)->Int{ifletidx=type(of:self).stringsArray.index(of:s){returnidx}else{type(of:self).stringsArray.append(s)returntype(of:self).stringsArray.count-1}}genericNames=fullName.components(separatedBy:"").map{getOrAdd($0)}forteaminteamsPlayedFor{genericNames=team.components(separatedBy:"").map{getOrAdd($0)}}}staticvarcharCount:Int{returnstringsArray.map{$0.utf8.count}.reduce(0,+)}}

WedefineaclasscalledPlayerProfileOptimised.HerewedefineastaticvariablecalledstringsArray,whichstoresdifferentstringsthatmayormaynotberepeated.Wethendefineanon-staticvariablecalledgenericNames,whichis

Page 90: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

goingtokeepanarrayofindices.

Ininitialisationmethod,wehaveaninnerfunctioncalledgetOrAdd,whichtakesastringasaparameterandreturnstheindexofthestringinstringsArrayifalreadyexisting,orreturnstheindexbyaddingittothestringsArrayarrayatthetailend.

WetheninitialisethegenericNamesarraybytakingthefullname,splittingitintoacomponentseparatedbyspace,andmappingitbycallingthefunctiongetOrAddwithaparameter.ThisletsusgetgenericNamestobeinitialisedtoasetofindicesthatcorrespondtothestringsinsidethestringsArrayarray.

Letusnowwriteamainfunctionandcheckthecharactercount:

funcmain(){letdhoni1=PlayerProfileOptimised("MahendraDhoni",["India,Chennai"])letkohli1=PlayerProfileOptimised("ViratKohli",["India,Bangalore"])letyuvi1=PlayerProfileOptimised("YuvrajSingh",["India,Punjab"])print("Totalnumberofcharsused:",PlayerProfileOptimised.charCount)}

main()

OutputintheXcodeconsole:

Totalnumberofcharsused:63

Forthesamedata,thenumberofcharactersreducedsignificantly.That’showFlyWeightdesignpatterncanbeusedforefficientstorageofdata.

Summary:

Whenyouareinasituationtostoredatathatmightcontainasignificantamountofduplicatedata,youcanuseFlyWeightdesignpattern.ThishelpsinreducingtheusageofavailableRAM.

Page 91: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

16)Structural-ProxyDesignPatternDefinition:

Talkingrealworldterms,yourdebitcardisaproxyofyourbankaccount.It’snotrealmoney,itbutcanbesubstitutedformoneywhenyouwanttobuysomething.

Proxyisastructuraldesignpatternthatuseswrapperclassestocreateastand-inforarealresource.Itisalsocalledsurrogate,handle,andwrapper.Proxyisusedtocoverthemainobject’scomplexlogicfromtheclientusingit.

Usage:

Assumewearedesigningasmallsoftwaretofilterapplicantsforthepositionofheadcoachofacricketteam.Theclientonlypassesthenumberofyearsoftheapplicant’sexperience,andweneedtowritealogictosayiftheapplicantisfitfortheroleornot,withoutdisturbingtheclient.

LetusseehowwecanuseProxydesignpatternhere:

importUIKitimportFoundation

protocolCoach{funcmentorTheTeam()}

classCricketCoach:Coach{

Page 92: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcmentorTheTeam(){print("MentoringtheCricketTeam")}}

WedefineaprotocolcalledCoach,whosemainjobistomentortheteam.ThenwedefineaclasscalledCricketCoachconformingtoCoachprotocol.

classCoachApplicant{varnumberOfYearsOfExperience:Intinit(numberOfYearsOfExperience:Int){self.numberOfYearsOfExperience=numberOfYearsOfExperience}}

WewriteaclasscalledCoachApplicant,whichtakesnumberOfYearsOfExperienceoftypeIntasparameterduringitsinitialisation.

NowwewriteaproxyconformingtoCoachprotocoltodefinethelogicinordertofilterapplicants.

classCricketCoachProxy:Coach{privateletcricketCoach=CricketCoach()privateletcoachApplicant:CoachApplicantinit(coachApplicant:CoachApplicant){self.coachApplicant=coachApplicant}funcmentorTheTeam(){ifcoachApplicant.numberOfYearsOfExperience>=8{cricketCoach.mentorTheTeam()

Page 93: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

}else{print("Notenoughexperiencetocoachtheteam")}}}

Ithastwoprivatevariables,oneoftypeCricketCoachandoneoftypeCoachApplicant.InmentorTheTeammethod,wedefinethelogic.Iftheexperienceofthecoachapplicantismorethan8years,heisthrough,otherwiseheisrejected.

Letusnowwriteourmainmethod:

funcmain(){letcoach:Coach=CricketCoachProxy(coachApplicant:CoachApplicant(numberOfYearsOfExperience:8))coach.mentorTheTeam()}

main()

OutputintheXcodeconsole:

MentoringtheCricketTeam

Keepchangingtheexperienceparameterandchecktheoutput.

funcmain(){letcoach:Coach=CricketCoachProxy(coachApplicant:CoachApplicant(numberOfYearsOfExperience:5))coach.mentorTheTeam()}

main()

OutputintheXcodeconsole:

Page 94: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

Notenoughexperiencetocoachtheteam

Inthefuture,ifwewanttochangethecriteriafrom8yearsto10yearsor6years,wedonothavetochangeanycodeattheclient’send.Wecanjustchangethelogicintheproxyandthingswillworkjustfine.

Summary:

Whenyouwanttocreateawrapperaroundamainobjecttohideitscomplexityfromtheclient,Proxydesignpatternsuitsthebest.Italsohelpsindelayingtheobject’sinitialisationsothatyoucanloadtheobjectsonlywhenitisneeded.

Page 95: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

PartFour:Behavioural

Page 96: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

17)Behavioural-ChainofResponsibilityDesignPattern

Definition:

ChainofResponsibilityisabehaviouraldesignpatternthatallowsustoavoidcouplingthesenderofarequesttoitsreceiverbygivingmultipleobjectsachancetohandletherequest.

Usage:

Assumewearebuildingasmallcricketvideogamewherewechoosetheplayercharacterswiththeirdefaultskills.Butthenwealsogiveprovisiontoaddskillboosterstotheplayercharactersasgamersgainsomecredits.LetusseehowwecanuseChainofResponsibilitytodesignsuchasystem.

importFoundation

classCricketer:CustomStringConvertible{varname:StringvarbattingSkillRating:IntvarbowlingSkillRating:IntvarfieldingSkillRating:Intinit(_name:String,_battingSkillRating:Int,_bowlingSkillRating:Int,_fieldingSkillRating:Int){self.name=nameself.battingSkillRating=battingSkillRatingself.bowlingSkillRating=bowlingSkillRatingself.fieldingSkillRating=fieldingSkillRating}

Page 97: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

vardescription:String{return"Cricketer:\(name)withbattingRating:\(battingSkillRating),bowlingRating:\(bowlingSkillRating),fieldingRating:\(fieldingSkillRating)"}}

WedefineaclasscalledCricketerconformingtoCustomStringConvertible.DuringitsinitialisationittakesparametersofnameoftypeString,battingSkillRatingoftypeInt,bowlingSkillRatingoftypeInt,andfieldingSkillRatingoftypeInt.

classSkillBooster{letcricketer:CricketervarskillBooster:SkillBooster?init(_cricketer:Cricketer){self.cricketer=cricketer}funcaddBooster(_booster:SkillBooster){ifskillBooster!=nil{skillBooster!.addBooster(booster)}else{skillBooster=booster}}funcplayTheGame(){skillBooster?.playTheGame()}}

WethendefineaclasscalledSkillBooster,whichismeanttobeabaseclassfordifferenttypesofboosters.IttakesaparameteroftypeCricketerduringitsinitialisation.WealsodefineanoptionalprivatevariableoftypeSkillBooster.Ithastwomethodsdefined,addBoosterandplayTheGame.addBoostertakesaparameteroftypeSkillBoosterandaddsittoexistingboostersafternilcheck.Otherwise,skillBoosterisassignedthevalueofincomingbooster.

Page 98: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

classBattingSkillBooster:SkillBooster{overridefuncplayTheGame(){print("AddingHookShotto\(cricketer.name)'sBatting")cricketer.battingSkillRating+=1super.playTheGame()}}

classBowlingSkillBooster:SkillBooster{overridefuncplayTheGame(){print("AddingReverseSwingto\(cricketer.name)'sBowling")cricketer.bowlingSkillRating+=1super.playTheGame()}}

classFieldingSkillBooster:SkillBooster{overridefuncplayTheGame(){print("AddingDiveCatchesto\(cricketer.name)'sFielding")cricketer.fieldingSkillRating+=1super.playTheGame()}}

WedefinedifferenttypesofskillboosterswithSkillBoosterasthebaseclass.Inalltheboosters,weoverridethefunctionplayTheGameandimprovethecorrespondingskillratingoftheplayercharacterby1.

classNoSkillBooster:SkillBooster{overridefuncplayTheGame(){print("Noboostersavailablehere")//don'tcallsuper}}

Wealsodefineadummyskillboosterjusttomakethegamemoreinteresting.

Letusnowwriteamainfunctiontoseethecodeinaction.

Page 99: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcmain(){letdhoni=Cricketer("Dhoni",6,3,7)print(dhoni)}

main()

OutputintheXcodeconsole:

Cricketer:DhoniwithbattingRating:6,bowlingRating:3,fieldingRating:7

Nowchangethemainmethodtothefollowing:

funcmain(){letdhoni=Cricketer("Dhoni",6,3,7)print(dhoni)letskillBooster=SkillBooster(dhoni)print("AddingBattingBoostertoDhoni")skillBooster.addBooster(BattingSkillBooster(dhoni))skillBooster.playTheGame()print(dhoni.description)}

main()

OutputintheXcodeconsole:

Cricketer:DhoniwithbattingRating:6,bowlingRating:3,fieldingRating:7AddingBattingBoostertoDhoniAddingHookShottoDhoni'sBattingCricketer:DhoniwithbattingRating:7,bowlingRating:3,fieldingRating:7

Page 100: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

WeaddBattingSkillBoostertoobjectdhonioftypeCricketer.Wecanchecktheoutputintheconsoleforanimprovedratingondhoni’sbattingskills.

Changethemainmethodtothefollowingandobservetheconsole:

funcmain(){letdhoni=Cricketer("Dhoni",6,3,7)letskillBooster=SkillBooster(dhoni)print("AddingBattingBoostertoDhoni")skillBooster.addBooster(BattingSkillBooster(dhoni))print("AddingBowlingBoostertoDhoni")skillBooster.addBooster(BowlingSkillBooster(dhoni))skillBooster.playTheGame()print(dhoni.description)}

main()

OutputintheXcodeconsole:

AddingBattingBoostertoDhoniAddingBowlingBoostertoDhoniAddingHookShottoDhoni'sBattingAddingReverseSwingtoDhoni'sBowlingCricketer:DhoniwithbattingRating:7,bowlingRating:4,fieldingRating:7

Summary:

UsetheChainofResponsibilitypatternwhenyoucanconceptualizeyourprogramasachainmadeupoflinks,whereeachlinkcaneitherhandlearequestorpassitupthechain.Itcanmodifyanexistingbehaviourbyoverridinganexistingmethodusinginheritance.

Page 101: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

18)Behavioural-StrategyDesignPatternDefinition:

Strategyisabehaviouraldesignpatternthatletsyoudefineasetofencapsulatedalgorithmsandenablesselectingoneofthematruntime.Animportantpointtoobserveisthatthesealgorithmimplementationsareinterchangeable.Inotherwords,strategyletsthealgorithmvaryindependentlyfromtheclientsthatuseit.

Usage:

ConsideranexampleofaBowlingMachinethatreleasesballsofdifferentcoloursbasedontheinputofspeedspecifiedbytheuser.Assumewehavethreedifferentspeeds:slow,medium,andfast,whichcorrespondstoyellow,green,andredcolouredballsrespectively.

importUIKit

enumCricketBall:String{caseslow="Yellow"casemedium="Green"casefast="Red"}

WenowdefineaprotocolReleaseCricketBallStrategy,whichhaspropertiesofspeedandthetypeofcricketball,andwhichalsodefinesamethodtoreleasetheball.

protocolReleaseCricketBallStrategy{varspeed:String{getset}varcricketBall:CricketBall{getset}

Page 102: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcreleaseBall()->String}

Wenowdefinethreenewclasses,oneeachforfast,medium,andslowballstrategies.

EachoftheclassesconformtoReleaseCricketBallStrategyprotocol.Forthesakeofsimplicity,wedefinespeedasastringwhichcanbeFast,Medium,orSlow.Eachoftheclasseshasaninitialiserthatdoesnottakeanyextraarguments.

releaseBallmethodreturnsastringimplyingthatitsimplementationreleasesaballwithspecifiedproperties.

classFastBallStrategy:ReleaseCricketBallStrategy{

varspeed="Fast"varcricketBall=CricketBall.fastinit(){}

funcreleaseBall()->String{return"Released\(speed)ballwithcolour\(cricketBall.rawValue)"}}

classMediumBallStrategy:ReleaseCricketBallStrategy{varspeed="Medium"varcricketBall=CricketBall.mediuminit(){}

funcreleaseBall()->String{return"Released\(speed)ballwithcolour\(cricketBall.rawValue)"}}

classSlowBallStrategy:ReleaseCricketBallStrategy{varspeed="Slow"varcricketBall=CricketBall.slowinit(){}

Page 103: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcreleaseBall()->String{return"Released\(speed)ballwithcolour\(cricketBall.rawValue)"}}

Now,wedefineaBowlingMachineclass,whichcanbeinitialisedatruntimebypassinganargumentofthetypeofstrategy.WemakeitconformtoCustomStringConvertible.

classBowlingMachine:CustomStringConvertible{privatevarreleaseCricketBallStrategy:ReleaseCricketBallStrategyprivatevarreturnString=""init(whatStrategy:ReleaseCricketBallStrategy){self.releaseCricketBallStrategy=whatStrategyreturnString=releaseCricketBallStrategy.releaseBall()}vardescription:String{returnreturnString}}

It’snowtimetoplaywithourbowlingmachine.Wedefineamethodnamedmain,whereweinitialiseBowlingMachineclasswithdifferenttypesofstrategies.

funcmain(){varbowlingMachine=BowlingMachine(whatStrategy:FastBallStrategy())print(bowlingMachine.description)

bowlingMachine=BowlingMachine(whatStrategy:SlowBallStrategy())print(bowlingMachine.description)

bowlingMachine=BowlingMachine(whatStrategy:MediumBallStrategy())print(bowlingMachine.description)

}

Now,runthemain()method.

Page 104: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

main()

OutputintheXcodeconsole:

ReleasedFastballwithcolourRedReleasedSlowballwithcolourYellowReleasedMediumballwithcolourGreen

Summary:

Strategypatternallowsustodefineasetofrelatedalgorithmsandallowstheclienttochooseanyofthealgorithmsatruntime.Itallowsustoaddanewalgorithmwithoutmodifyingexistingalgorithms.

19)Behavioural-CommandDesignPattern:

Definition:

ThedefinitionofCommandprovidedintheoriginalGangofFourbookonDesignPatternsstates:

Encapsulatearequestasanobject,therebylettingyouparameterizeclientswithdifferentrequests,queueorlogrequests,andsupportundoableoperations.

Commandisabehaviouraldesignpatternthatdecouplestheobjectinvokingtheoperationfromtheobjectthatknowshowtoperformit.Itallowsustoturnrequestsintostand-aloneobjectsbyprovidingrequestobjectswithallthenecessaryinformationfortheactiontobetaken.Usage:Letusconsideradecisionreviewsysteminacricketmatchwheretheon-fieldumpireisnotsureifabatsmanisoutornot.ThisumpirethenaskstheTVumpiretocheckTVreplaysandmakeadecision.TheTVumpirethencommandstheTVoperatortoshowOUT/NOTOUTonthescreen,dependinguponthedecisionmade.Let’sseehowwecandesignsuchasystemwiththehelpofCommanddesignpattern.importUIKit

Page 105: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

importFoundation

protocolCommand{funcexecute()}

WedefineaprotocolnamedCommandwithafunctionnamedexecute.classScreenDisplay{privatevarshowOutOnDisplay=falsefuncisBatsmanOut(){showOutOnDisplay=trueprint("BatsmanisOUT")}funcisBatsmanNotOut(){showOutOnDisplay=falseprint("BatsmanisNOTOUT")}

}

WethendefineaclasscalledScreenDisplay,whichisusedtodisplaythedecisionmadebytheTVumpire.IthasaprivatevariablenamedshowOutOnDisplay,whichisinitialisedtofalse.Ithastwomethodsdefined.Basedontheboolproperty,thesemethodsshowbatsmanOUT/NOTOUTonthescreen.classBatsmanOutCommand:Command{varscreenDisplay:ScreenDisplayinit(_screenDisplay:ScreenDisplay){self.screenDisplay=screenDisplay}funcexecute(){screenDisplay.isBatsmanOut()}}

Page 106: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

classBatsmanNotOutCommand:Command{varscreenDisplay:ScreenDisplayinit(_screenDisplay:ScreenDisplay){self.screenDisplay=screenDisplay}funcexecute(){screenDisplay.isBatsmanNotOut()}}

Wethenwritetwoclasses,BatsmanOutCommandandBatsmanNotOutCommand,conformingtoCommandprotocol.BoththeseclassestakeaparameteroftypeScreenDisplayduringtheirinitialisation.ThenwewritethedefinitionofexecutemethodbycallingisBatsmanOut/isBatsmanNotOutonScreenDisplayobject.

classDisplaySwitch{varcommand:Commandinit(_command:Command){self.command=command}funcpressSwitch(){command.execute()}}

Finally,wewriteaclasscalledDisplaySwitch,whichtakesanobjectoftypeCommandforitsinitialisation.WedefineamethodcalledpressSwitch,whichimplementstheexecutemethodonCommandobject.Letuswriteourmainmethodandseeourcodeinaction.funcmain(){letscreenDisplay=ScreenDisplay()letoutCommand=BatsmanOutCommand(screenDisplay)letnotOutCommand=BatsmanNotOutCommand(screenDisplay)

Page 107: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

letdisplaySwitchForOut=DisplaySwitch(outCommand)displaySwitchForOut.pressSwitch()letdisplaySwitchForNotOut=DisplaySwitch(notOutCommand)displaySwitchForNotOut.pressSwitch()}

main()

WetakeaninstanceofScreenDisplayandpassittoBatsmanOutCommandandBatsmanNotOutCommandfortheirinitialisations.

Then,basedonthedecisionmadebytheTVumpire,weinitialiseDisplaySwitchusingoutCommand/notOutCommandastheparameters.

OutputintheXcodeconsole:

BatsmanisOUTBatsmanisNOTOUT

Summary:

Whenyouwanttoencapsulatethelogicaldetailsofanoperationinaseparateentityanddefinespecificinstructionsforapplyingthecommand,Commanddesignpatternservesyouthebest.Italsohelpsincreatingcompositecommands.

Page 108: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

20)Behavioural-IteratorDesignPatternDefinition:

Iterationincodingisacorefunctionalityofvariousdatastructures.Aniteratorfacilitatesthetraversalofadatastructure.Iteratorisabehaviouraldesignpatternthatisusedtosequentiallyaccesstheelementsofanaggregateobjectwithoutexposingitsunderlyingimplementation.

Usage:

Assumewearemakingalistoftopcricketersinacurrentlot,whichincludestheirnameandteamname.Wewillnowseehowtouseaniteratortotraversethroughthelistandprinttheprofileofeachcricketer.

Letuswritesomecodenow:

importFoundationstructCricketer{letname:Stringletteam:String}

WedefineastructnamedCricketer,whichstoresnameandteamasStringproperties.

structCricketers{letcricketers:[Cricketer]}

WedefineanotherstructnamedCricketers,whichstorescricketersarrayof

Page 109: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

customtypeCricketer.

structCricketersIterator:IteratorProtocol{privatevarcurrent=0privateletcricketers:[Cricketer]init(_cricketers:[Cricketer]){self.cricketers=cricketers}mutatingfuncnext()->Cricketer?{defer{current+=1}ifcricketers.count>current{returncricketers[current]}else{returnnil}}}

extensionCricketers:Sequence{funcmakeIterator()->CricketersIterator{returnCricketersIterator(cricketers)}}

Thisiswherethemagichappens.WedefineastructnamedCricketersIteratorconformingtoIteratorProtocol.ThenwewriteanextensionforCricketersthatconformstoSequenceprotocol.

Applesays,

“TheIteratorProtocolprotocolistightlylinkedwiththeSequenceprotocol.Sequencesprovideaccesstotheirelementsbycreatinganiterator,whichkeepstrackofitsiterationprocessandreturnsoneelementatatimeasitadvances

Page 110: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

throughthesequence.Wheneveryouuseafor-inloopwithanarray,set,oranyothercollectionorsequence,you’reusingthattype’siterator.Swiftusesasequence’sorcollection’siteratorinternallytoenablethefor-inlooplanguageconstruct.Usingasequence’siteratordirectlygivesyouaccesstothesameelementsinthesameorderasiteratingoverthatsequenceusingafor-inloop.”

Backtoourcode,wedefinedtwoprivateproperties,currentoftypeInt(withdefaultvalueof0)andanarraycricketersoftypeCricketer.

WedefineamethodnextthatreturnsanobjectoftypeCricketer(noticetheoptional-wemaynothaveanyelementleftinthearrayafterwereachthelastelement).

Letusnowwriteourmainmethod:

funcmain(){letcricketers=Cricketers(cricketers:[Cricketer(name:"Kohli",team:"India"),Cricketer(name:"Steve",team:"Australia"),Cricketer(name:"Kane",team:"Kiwis"),Cricketer(name:"Root",team:"England")])forcrickincricketers{print(crick)}}

main()

OutputintheXcodeconsole:

Cricketer(name:"Kohli",team:"India")Cricketer(name:"Steve",team:"Australia")Cricketer(name:"Kane",team:"Kiwis")Cricketer(name:"Root",team:"England")

Addingthecodesnippetforanotherself-explanatoryexamplehere,whichwouldenhanceyourunderstanding:

importFoundation

Page 111: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

classCricketer:Sequence{vartotalRunsScored=[Int](repeating:0,count:3)privatelet_testRuns=0privatelet_ODIRuns=1privatelet_t20Runs=2vartestRuns:Int{get{returntotalRunsScored[_testRuns]}set(value){totalRunsScored[_testRuns]=value}}varODIRuns:Int{get{returntotalRunsScored[_ODIRuns]}set(value){totalRunsScored[_ODIRuns]=value}}vart20Runs:Int{get{returntotalRunsScored[_t20Runs]}set(value){totalRunsScored[_t20Runs]=value}}vartotalRuns:Int{returntotalRunsScored.reduce(0,+)}subscript(index:Int)->Int{get{returntotalRunsScored[index]}set(value){totalRunsScored[index]=value}}funcmakeIterator()->IndexingIterator<Array<Int>>{

Page 112: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

returnIndexingIterator(_elements:totalRunsScored)}}

funcmain(){letcricketer=Cricketer()cricketer.testRuns=1200cricketer.ODIRuns=1800cricketer.t20Runs=600

print("TotalRunsScored=\(cricketer.totalRuns)")forsincricketer{print(s)}}

main()

OutputintheXcodeconsole:

TotalRunsScored=360012001800600

Summary:

Whenyouareinasituationwhereyouwanttohidethecomplexityofadatastructurefromclientsandhaveasingleinterfacefortraversingthedatastructures,Iteratordesignpatternservesyouthebest.

Page 113: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

21)Behavioural-InterpreterDesignPatternDefinition:

Interpretersarepresenteverywherearoundus.Indesignpatterns,interpreterisacomponentthatprocessesstructuredtextdata.Itfallsunderbehaviouraldesignpattern.

Usage:

Letususeinterpreterdesignpatterntogetawaytoprinttheelementsofacollectionobjectinsequentialmanner.

importUIKitimportFoundation

protocolInterpreter{funchasNext()->Boolfuncnext()->String}

protocolContainer{funcgetInterpreter()->Interpreter}

WedefinetwoprotocolsnamedInterpreterandContainer.Interpreterhastwofunctionstocheckifthenextelementispresentinarrayaftereveryiterationandtoreturntheelement(ifpresent).Containerhasamethodtoreturntheinterpreter.

Page 114: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

classNameRepo:Container{letnames=["India","Australia","England","NewZealand"]funcgetInterpreter()->Interpreter{returnNameInterpreter(names)}}

WethendefineaclasscalledNameRepoconformingtoContainerprotocol.Inourmainfunction,weuseiteratortoprintallthevaluespresentinthenamesarray.

privateclassNameInterpreter:Interpreter{varindex=-1varnames=[String]()init(_names:[String]){self.names=names}funchasNext()->Bool{ifindex<names.count{returntrue}returnfalse}funcnext()->String{ifself.hasNext(){index=index+1returnnames[index]}else{return""}}}

WedefineaclasscalledNameIteratorconformingtoIteratorprotocol.IttakesaparameteroftypeStringarrayduringitsinitialisation.

Page 115: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

Letuswriteamainfunctiontoseethecodeinaction.

funcmain(){letnr=NameRepo()letinterpreter=NameInterpreter(nr.names)for_innr.names{interpreter.hasNext()print(interpreter.next())}}

main()

OutputintheXcodeconsole:

IndiaAustraliaEnglandNewZealand

Summary:

UsetheInterpreterpatternwhenthereisalanguagetointerpret,andyoucanrepresentstatementsinthelanguageasabstractsyntaxtrees.

Page 116: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

22)Behavioural-MediatorDesignPatternDefinition:Mediatorisabehaviouraldesignpatternthatletsusdefineacomponentthatencapsulatesrelationshipsbetweenasetofcomponents(thatabsolutelymakesnosensetohavedirectreferencestooneanother)tomakethemindependentofeachother.Mediatorpatternpreventsdirectcommunicationbetweenindividualcomponentsbysendingrequeststoacentralcomponentthatknowswheretoredirectthoserequests.Usage:LetusassumewearedesigningaTVumpiredecisionreviewsystemforacricketmatch.Whenanon-fieldumpiredoesnothaveenoughevidencetoruleabatsmanout,hesendstherequesttotheTVumpirewhotakesalookatthereplaysandsendsacommandtothemonitoroperatorwhodisplaysthefinaldecisiononthebigscreen.Let’sseehowwecanuseMediatordesignpatterntodesignsuchadecisionreviewsystem.importUIKitimportFoundation

protocolCommand{funcdisplayStatus()}

WewriteaprotocolCommandthatdefinesafunctioncalleddisplayStatus.

protocolRemoteUmpire{funcregisterTVDisplay(tvDisplay:TVDisplay)funcregisterTVOperator(tvOperator:TVOperator)funcisDecisionMade()->BoolfuncsetDecisionStatus(status:Bool)

Page 117: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

}

WewriteanotherprotocolcalledRemoteUmpirethatdefinesahandfuloffunctionalities.

1. 1) Theremoteumpire(alsocalledTVumpire)hastoregisterforTVdisplaybypassingaparameteroftypeTVDisplay(tobedefined).

2. 2) Theremoteumpire(alsocalledTVumpire)hastoregisterforTVoperatorbypassingaparameteroftypeTVOperator(tobedefined).

3. 3) AfunctionnamedisDecisionMade,whichreturnsaboolean.4. 4) Anotherfunctiontosetthestatusofdecisionbypassingaboolean

argument.

classTVOperator:Command{vartvUmpire:TVUmpireinit(_tvUmpire:TVUmpire){self.tvUmpire=tvUmpire}funcdisplayStatus(){iftvUmpire.isDecisionMade(){print("DecisionMadeandBatsmaninOUT")tvUmpire.setDecisionStatus(status:true)}else{print("DecisionPending")}}funcgetReady(){print("ReadytoDisplayDecision")}}

WedefineaclasscalledTVOperatorconformingtoCommandprotocol.IttakesanobjectoftypeTVUmpire(tobedefined)duringitsinitialisation.

Page 118: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

IthasamethodnameddisplayStatus,whichbasedontheTVumpire’sdecision,displaysabatsmanoutornotonthebigscreeninthestadium.

classTVDisplay:Command{vartvUmpire:TVUmpireinit(_tvUmpire:TVUmpire){self.tvUmpire=tvUmpiretvUmpire.setDecisionStatus(status:true)}

funcdisplayStatus(){print("DecisionmadeandpermissiongrantedtodisplaythedecisiononTVDisplay")tvUmpire.setDecisionStatus(status:true)}}

WedefineaclasscalledTVDisplayconformingtoCommandprotocol.ThisclassalsotakesanobjectoftypeTVUmpire(tobedefined)foritsinitialisation.ItsmainfunctionalityistodisplaythestatusofthedecisionbasedontheinputgivenbytheTVumpire.

classTVUmpire:RemoteUmpire{privatevartvOperator:TVOperator?privatevartvDisplay:TVDisplay?privatevardecisionMade:Bool?funcregisterTVDisplay(tvDisplay:TVDisplay){self.tvDisplay=tvDisplay}funcregisterTVOperator(tvOperator:TVOperator){self.tvOperator=tvOperator}funcisDecisionMade()->Bool{returndecisionMade!}

Page 119: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcsetDecisionStatus(status:Bool){self.decisionMade=status}}

WethendefineourmostimportantclassnamedTVUmpireconformingtoRemoteUmpireprotocol.Ithasthreeprivateoptionalvariablesdefined:tvOperatoroftypeTVOperator,tvDisplayoftypeTVDisplay,andabooleannameddecisonMade.

ItregistersforTVdisplaybyassigningitspropertyoftvDisplaytoparameteroftypeTVDisplayfromthemethodregisterTVDisplay.

ItregistersforTVoperatorbyassigningitspropertyoftvOperatortoparameteroftypeTVOperatorfromthemethodregisterTVOperator.

Let’snowwriteourmainfunctionandseehowtheabovecodecomesintoaction.

funcmain(){lettvUmpire=TVUmpire()lettvDisplayAtGround=TVDisplay(tvUmpire)lettvOperatorAtGround=TVOperator(tvUmpire)tvUmpire.registerTVDisplay(tvDisplay:tvDisplayAtGround)tvUmpire.registerTVOperator(tvOperator:tvOperatorAtGround)tvOperatorAtGround.getReady()tvDisplayAtGround.displayStatus()tvOperatorAtGround.displayStatus()}

main()

WetakeaninstanceofTVUmpireandpassthesameinstancetoinitialiseTVDisplayandTVOperator.

TVUmpirethenregistersforTVDisplayandTVUmpirebypassinginstancesofTVDisplayandTVUmpirerespectively.

Page 120: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

OncetheTVumpirehasmadehisdecision,TVoperatoronthegroundgetsreadytodisplaythestatusofthedecisionaccordinglyonthedisplayattheground.

OutputintheXcodeconsole:ReadytoDisplayDecisionDecisionmadeandpermissiongrantedtodisplaythedecisiononTVDisplayDecisionMadeandBatsmaninOUT

Summary:

UseaMediatordesignpatternwhenthecomplexityoftheobjectcommunicationbeginstohinderobjectreusability.Mediatorengagesintwo-waycommunicationwithitsconnectedcomponents.

Page 121: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

23)Behavioural-MementoDesignPatternDefinition:

Mementoisabehaviouraldesignpatternthatletsussavethesnapshotsoftheobject’sinternalstateateverypointoftimewithoutexposingitsinternalstructure.Thishelpsusinrollingbacktothestatewhenthesnapshotwastaken.

Usage:

Assumeweareaddingthestatsofacricketer(numberofrunsscored)yearbyyearinourprogram,andatsomepointwewanttotracebacktoayearinthepastandcheckhisstatsupuntilthatpointintime.

Let’sdefineaMementoclass,whichtakesanargumentofnumberofrunsscoredinitsinitialisation.

importUIKitclassMemento{letnumberOfRunsScored:Intinit(_numberOfRunsScored:Int){self.numberOfRunsScored=numberOfRunsScored}}

Let’sassumeanimaginaryhardwarenamedStatsHolder,whichdisplaysthestats.ItconformstoCustomStringConvertibleprotocol.Ittakesanargumentofnumberofrunsscoredinitsinitialisation.

classStatsHolder:CustomStringConvertible{

Page 122: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

privatevarnumberOfRunsScored:Intprivatevarsnapshots:[Memento]=[]privatevarcurrentIndex=0

init(_numberOfRunsScored:Int){self.numberOfRunsScored=numberOfRunsScoredsnapshots.append(Memento(numberOfRunsScored))}vardescription:String{return"TotalRunsscored=\(numberOfRunsScored)"}}

Allthepropertiesaredeclaredprivate,aswedonotwanttoexposetheinternalstructureofourhardwaretotheclient.

WemaintainanarrayofsnapshotsoftypeMementosothatwecanrestorepaststatsjustbypassingamemento.Whentheclassisinitialised,currentIndexstartsatzero.

Wenowaddafunctionnamed‘addStatsToHolder’,whichtakesnumberofrunsasparameterandreturnsusasnapshotoftypeMemento.

funcaddStatsToHolder(_runsToBeAdded:Int)->Memento{numberOfRunsScored+=runsToBeAddedletsnapshot=Memento(runsToBeAdded)snapshots.append(snapshot)currentIndex+=1returnsnapshot}

WekeepappendingthesnapshotofMementoinitialisedtothearrayandincrementthecurrentIndexby1.

WeneedafunctionthatletsusrestoreapaststatbypassingaparameteroftypeMemento.

Page 123: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcrestoreToPastStat(_memento:Memento?){ifletsnap=memento{numberOfRunsScored=snap.numberOfRunsScoredsnapshots.append(snap)currentIndex=snapshots.count-1}}

NotethatmementoparameterisoptionalbecauseforthecurrentIndexvalueof0,wedonothaveanythingtorestoreto.WechangethenumberOfRunsScoredtothevalueofsnapshot.WeappendthesnapshotofparametertoourarrayanddecrementthecurrentIndexby1.

Now,weneedmethodstoundoandredostats.

funcundoAStat()->Memento?{ifcurrentIndex>0{currentIndex-=1letsnap=snapshots[currentIndex]numberOfRunsScored=snap.numberOfRunsScoredreturnsnap}returnnil}funcredoAStat()->Memento?{ifcurrentIndex+1<snapshots.count{currentIndex+=1letsnap=snapshots[currentIndex]numberOfRunsScored=snap.numberOfRunsScoredreturnsnap}returnnil}

NotethatthereturnedMementoisoptional,aswemaynothaveanythingtoundoforthefirstadditionofthestatandnothingtoredoafterthefinaladditionofthestat.Inthesecases,wereturnanil.

Page 124: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

InundoAStatmethod,wecheckifthecurrentIndex>0.Ifno,wereturnnil.Ifyes,wedecrementthecurrentIndexby1andgetthesnapshotatcurrentIndex.WethenchangethenumberOfRunsScoredtothevaluepresentinthesnapshot.

InredoAStatmethod,wecheckifthecurrentIndexislessthanthecountofsnapshotsdecrementedby1.Ifno,wereturnnil.Ifyes,weincrementthecurrentIndexby1andgetthesnapshotatthecurrentIndex.WethenchangethenumberOfRunsScoredtothevaluepresentinthesnapshot.

WearedonewithoursetupofMementodesignpattern.Let’sseehowweimplementthispattern.

funcmain(){letstatsHolder=StatsHolder(1200)//1200isthefirststat(numberofruns)weaddtostatsholderletstat1=statsHolder.addStatsToHolder(1400)letstat2=statsHolder.addStatsToHolder(700)print("a-",statsHolder)//undoTopmostoperationstatsHolder.undoAStat()print("b-",statsHolder)//undoTopmostoperationstatsHolder.undoAStat()print("c-",statsHolder)//restoreToStat2statsHolder.redoAStat()print("d-",statsHolder)//Thereisnomemento/snapshotwhentheStatsHolderisinitialised}

Inthemainmethod,weinitialisetheStatsHolderbypassing1200runsasparameter.WethenaddacoupleofstatsbyusingaddStatsToHoldermethodbypassing1400and700runsasparameters.

WethenundothelasttwostatadditionsbyusingundoAStatmethodon

Page 125: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

statsHolder.WethenredothelastoperationbyusingredoAStatmethodonstatsHolder.

Nowrunthemain()method.

main()

OutputintheXcodeconsole:

a-TotalRunsscored=3300b-TotalRunsscored=1400c-TotalRunsscored=1200d-TotalRunsscored=1400

Initially,weaddedthreestats,whichtakesthetotalto3300.Thenweundooneoperation,whichtakesthetotalto1400(subtracting700).Onemoreundotakesustotheinitialstateof1200.Weredothelastundooperation,whichagaintakesusbackto1400.

Summary:

Ifyourapplicationdemandstosavecheckpointsastheuserprogressesthroughtheapp,goforMementodesignpattern.Thishelpsinrestoringthecheckpointsatalaterpointoftime.

Page 126: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

24)Behavioural-NullObjectDesignPatternDefinition:

InObjectOrientedProgramming,nullisanobjectthathasnoreferencedvalue.WhenanobjectAtriestouseanobjectB,objectAassumesthatobjectBisnotnil.WhenthereisnooptionoftellingAnottouseinstanceofBwhenithasnovalue,NullObjectdesignpatterncomesintoplay.NullObjectisabehaviouraldesignpatternthatsimplifiestheuseofundefineddependencies.

Usage:

Let’sseehowthisdesignpatterncanbeusedincode.

Assumewehaveacricketmatchhappeningatastadiumandusersreceiveliveupdatesofthescoreontheirdevices(iPadoriPhone).Bydefault,weshowthescoreontheinterface.ButoniPad,alongwiththelivescore,wealsoshowbowlersandbatsmanstats,asthereisavailablescreenestate.ButthesameinterfacelookscongestedonaniPhonedisplay.So,werefrainourselvesfromshowingbatsmanandbowlerstatsforiPhonedisplay.

importFoundation

protocolLog{funcbowlerStatsFromCurrentMatch(_stats:String)funcbatsmenStatsFromCurrentMatch(_stats:String)}

WehaveaprotocolnamedLogthatdefinestwomethodstoshowbowlersandbatsmenstatsfromthecurrentmatch,whichtakesstatsasinputinString

Page 127: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

format.

classStatsDisplayLog:Log{funcbowlerStatsFromCurrentMatch(_stats:String){print(stats)}funcbatsmenStatsFromCurrentMatch(_stats:String){print(stats)}}

classNoDisplayStatsLog:Log{funcbowlerStatsFromCurrentMatch(_stats:String){}funcbatsmenStatsFromCurrentMatch(_stats:String){}}

Wenowdefinetwoclasses,StatsDisplayLogandNoDisplayStatsLog,bothconformingtoLogprotocol.Theonlydifferenceistheimplementationofthesemethodsintheclasses,whichisverystraightforward.WeshowthestatsinStatsDisplayLoganddonotshowanystatsinNoDisplayStatsLog.

classUserInterface{varlog:LogvarrunsScored=0varwicketsTaken=0

init(_log:Log){self.log=log}

funcwicketTaken(){wicketsTaken+=1log.bowlerStatsFromCurrentMatch("TotalWickets:\(wicketsTaken)")}

Page 128: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcrunsScored(numberOFRunsScored:Int){runsScored+=numberOFRunsScoredlog.batsmenStatsFromCurrentMatch("TotalRuns:\(runsScored)")}}

WedefineaclasscalledUserInterface,whichtakescareofthelogicbehindwhattodisplaytotheusersontheirdevices.ThisclasstakesaparameteroftypeLogduringitsinitialisation.Therearetwomethodstoupdatethenumberofwicketstakenandnumberofrunsscored,andwhenaneventhappensinthematch.WiththehelpofinstanceofLogclass,thesestatsareshownontheinterface.Let’snowwriteafunctioncalledmain.

funcmain(){letipadLog=StatsDisplayLog()letiPAdUserInterface=UserInterface(ipadLog)iPAdUserInterface.runsScored(numberOFRunsScored:4)iPAdUserInterface.runsScored(numberOFRunsScored:3)iPAdUserInterface.wicketTaken()}

main()OutputintheXcodeconsole:

TotalRuns:4TotalRuns:7TotalWickets:1ThisiswhatauserseesonhisiPad,aswearetakinganinstanceofStatsDisplayLogforiPadinterface.Now,addthebelowcodetothemainfunction:

letiPhoneLog=NoDisplayStatsLog()letiPhoneUserInterface=UserInterface(iPhoneLog)iPhoneUserInterface.runsScored(numberOFRunsScored:6)iPhoneUserInterface.runsScored(numberOFRunsScored:2)

Page 129: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

WecanobservethatthereisnochangeintheoutputintheXcodeconsole.ThisisbecauseweareusinganinstanceofNoDisplayStatsLog,whichisusedforaniPhoneinterface.

Summary:

NullObjectdesignpatterncanbeusedinsituationswhererealobjectsarereplacedbynullobjectswhentheobjectisexpectedtodonothing.

Page 130: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

25)Behavioural-ObserverDesignPatternDefinition:

Observerdesignpatternisusedwhenwewantanobject(calledobservable),whichmaintainsalistofobjects(calledobservers),tonotifythemwhenobservabledoessomethingoritspropertieschangeorsomeexternalchangeoccurs.Theprocessofnotifyingisdonethrougheventsgeneratedbyobservable.

Usage:

importFoundation

protocolInvocable:class{funcinvoke(_data:Any)}

publicprotocolDisposable{funcdispose()}

publicclassEvent<T>{publictypealiasEventHandler=(T)->()vareventHandlers=[Invocable]()publicfuncraise(_data:T)

Page 131: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

{forhandlerineventHandlers{handler.invoke(data)}}publicfuncaddHandler<U:AnyObject>(target:U,handler:@escaping(U)->EventHandler)->Disposable{letsubscription=Subscription(target:target,handler:handler,event:self)eventHandlers.append(subscription)returnsubscription}}

classSubscription<T:AnyObject,U>:Invocable,Disposable{weakvartarget:T?lethandler:(T)->(U)->()letevent:Event<U>init(target:T?,handler:@escaping(T)->(U)->(),event:Event<U>){self.target=targetself.handler=handlerself.event=event}funcinvoke(_data:Any){iflett=target{handler(t)(dataas!U)}}funcdispose()

Page 132: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

{event.eventHandlers=event.eventHandlers.filter{$0asAnyObject?!==self}}}

Thisishowwedefineobserversandobservables.YoucanfeelfreetocopyandpastethiswithoutanymodificationstouseObserverdesignpatterns.Iwillnotbediscussingitindetail,asthemainintentionistolearnaboutdesignpatterns.

Now,assumeacricketmatchishappening.Thereisascoreboardontheground,whichisupdatedwheneveranyeventhappens(runhit/batsmanout/fieldertakingcatch,etc).Forthesakeofsimplicity,letusonlytalkaboutthebattingteammakingrunsevent.

Letusdefinescoreboardclass.

classScoreBoardInTheGround{letbatsmenHitRun=Event<Int>()init(){}funcupdateScore(){}}

ScoreBoardInTheGroundcanbeinitialisedwithoutanyarguments.IthasaneventbatsmenHitRunandamethodtoupdatethescore.Thisisourobservable,whichbroadcastseventswheneverbatsmanhitsruns.

Whenthescoreboardonthegroundisupdated,thesameupdatehastoreachtheserversofamobileapp,wheremillionsofpeoplefollowthematchupdates.Therearemanysuchservers,whicharecalledobservers,andtheyneedtoknowwheneverthestateofScoreBoardInTheGroundchanges.Letusdefineourobservableclass.

classScoreUpdateInServers{init(){letscoreBoard=ScoreBoardInTheGround()

Page 133: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

letsubscriber=scoreBoard.batsmenHitRun.addHandler(target:self,handler:ScoreUpdateInServers.showScoreInApp)//simualtebatsmanhittingrunsinthegroundscoreBoard.batsmenHitRun.raise(6)//getridofthedescriptionsubscriber.dispose()}funcshowScoreInApp(score:Int){print("ScoreNowis:\(score)runs")}}

WhenScoreUpdateInServersisinitialised,wetakeaninstanceofScoreBoardInTheGroundandaddasubscribertobatsmanHitRuneventwiththehelpofahandler.

Thenwearesimulatinganeventofabatsmanhittingsixrunsinthematchandthescoreboardonthegroundneedstobroadcastthiseventtotheservers.Thenwealsogetridofthesubscriptionwiththehelpofadisposefunction.

Serversofthemobileapphaveamethodtoshowthescoreinthedisplay,whichtakesthescoreastheinputparameter.Forthesakeofsimplicity,wejustprintthescoreinthismethod.

Now,addthebelowcodesnippettoseethecodeinaction.

funcmain(){letdummy=ScoreUpdateInServers()}

main()

OutputintheXcodeconsole:

ScoreNowis:6runs

Summary:

Page 134: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

Ifyouwanttosubscribe/unsubscribetoobjectsdynamically,Observerdesignpatternisthebestpossibleway.Notethefactthatsubscribersarenotifiedinrandomorder.

Page 135: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

26)Behavioural-StateDesignPatternDefinition:

Stateisabehaviouraldesignpatternthatisusedtoalterthebehaviourofanobjectasitsinternalstatechanges.Theobjectwillappeartochangeitsclass.

Usage:

Let’sassumeaplayerauctionisgoingonforsomeprivatecricketleague.Aplayeriseitherinunsoldstateorsoldstatewiththenameoftheteamattachedtohim.WenowseehowStatedesignpatterncanbeusedinthiscontext.

importUIKit

protocolState{funcisSold(playerAuction:PlayerAuction)->BoolfuncwhichTeam(playerAuction:PlayerAuction)->String?}

WehaveaprotocolnamedState,whichdefinestwomethods:

1. 1) isSoldtakesanobjectoftypePlayerAuction(tobedefined)andreturnstrue/false.

2. 2) whichTeamtakesanobjectoftypePlayerAuction(tobedefined)andreturnsanoptional(asanunsoldplayerdoesnothaveanyteamassociatedwithhim).

Wethendefinestatesinwhichaplayerobjectcanbein.

Page 136: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

classIsUnsoldState:State{funcisSold(playerAuction:PlayerAuction)->Bool{returnfalse}funcwhichTeam(playerAuction:PlayerAuction)->String?{returnnil}}

classIsSoldState:State{letteamName:Stringinit(teamName:String){self.teamName=teamName}funcisSold(playerAuction:PlayerAuction)->Bool{returntrue}funcwhichTeam(playerAuction:PlayerAuction)->String?{returnteamName}}

1. 1) FirstoneisIsUnsoldStateanditconformstoStateprotocol.ItreturnsfalsewhencalledisSoldmethodandanilwhencalledwhichTeam.

2. 2) SecondoneisIsSoldStateanditconformstoStateprotocol.IttakestheargumentofteamNameoftypeStringforitsinitialisation.ItreturnstruewhencalledisSoldmethodandanilwhencalledwhichTeam.

Wenowdefinethemostimportantclass,PlayerAuction:

classPlayerAuction{privatevarstate:State=IsUnsoldState()varisSold:Bool{get{returnstate.isSold(playerAuction:self)

Page 137: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

}}varteamName:String?{get{returnstate.whichTeam(playerAuction:self)}}funcchangeStateToSold(teamName:String){state=IsSoldState(teamName:teamName)}funcchangeStateToUnSold(){state=IsUnsoldState()}}

IthasaprivatevariableoftypeState,whichhasadefaultvalueofIsUnsoldState.Wethengetandsettwovariables,isSoldandteamName,withthehelpofstatepropertyandpassinganargumentoftypeself.

Wethendefinetwomethods:

1. 1) changeStateToSold,whichtakesanargumentoftypeString,andthestateofplayerobjectischangedtoIsSoldStatebypassingtheargument.

2. 2) changeStateToUnsold,whereplayer’sstateischangedtoinstanceofIsUnsoldState.

Letusnowwriteamainmethodtoseethisdesignpatterninaction:

funcmain(){letplayerAuction=PlayerAuction()print(playerAuction.isSold,playerAuction.teamName)playerAuction.changeStateToSold(teamName:"ChennaiSuperKings")

Page 138: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

print(playerAuction.isSold,playerAuction.teamName!)}

main()

WestartwithtakinganinstanceofclassPlayerAuction.ThenchangethedefaultstatusofunsoldtosoldstatebypassingateamnameChennaiSuperKings.

OutputintheXcodeconsole:

falseniltrueChennaiSuperKings

Fortheunsoldstate,isSoldreturnsafalseandwhichTeamreturnsnil.Asthestateischanged,isSoldreturnstrueandwhichTeamreturnsChennaiSuperKings.

Summary:

Whenyouareinasituationwherethebehaviourofanobjectshouldbeinfluencedbyitsstate,thenumberofstatesisbig,andthestaterelatedcodechangesfrequently,Statedesignpatternservesyourpurpose.

Page 139: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

27)Behavioural-TemplateDesignPatternDefinition:

Templateisabehaviouraldesignpatternthathelpstodividealgorithmsintocommonpartsandspecificsthroughinheritance.Insimplewords,baseclassdeclaresalgorithm‘placeholders’andderivedclasseswritetheconcreteimplementationofplaceholders(oralgorithms).

Usage:

Letusconsiderasituationwherewearebuildingatemplateforacricketteam.Themainmottoistodecidetheteam’scompositionbasedonthepitchandweatherconditions(howmanybatsmentoplay,howmanybowlerstoplay,howmanyfastbowlers,howmanyspinners,etc).Asingletemplateforallthepitchconditionswillnothelp.

LetusseehowwecanuseTemplatedesignpatternforthesameusecase.

importUIKitimportFoundation

classTeamTemplate{

funcbuildTeam(){pickBatsmen()pickBowlers()pickAllRounders()pickWicketKeeper()print("\nTeamSetForthematch")}

Page 140: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcpickBatsmen(){}funcpickBowlers(){}funcpickAllRounders(){}privatefuncpickWicketKeeper(){print("OnlyoneWKavailableandheispickedbydefault")}}

WedefineabaseclasscalledTeamTemplate,whichwilllaterbeinheritedbyotherclasses.

WedefineafunctioncalledpickWicketKeeperanddeclareitprivatebecausethereisonlyoneWicketKeeperavailableinthesquad,andheisintheplayingteambydefault.Noonehastheauthoritytochangeit.

WealsodefineemptyfunctionscalledpickBatsmen,pickBowlers,andpickAllRounders,whoseimplementationsaredefinedinthesubclassesthroughinheritance.

WenowdefinethreedifferentclasseswithTeamTemplateasBaseClasswherewewritetheconcreteimplementationofteamBuildingmethod.

classSeamingPitchTeamTemplate:TeamTemplate{overridefuncpickBatsmen(){print("Picking6batsmen")}overridefuncpickBowlers(){print("Picking3FastBowlers")

Page 141: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

}overridefuncpickAllRounders(){print("Picking1PaceAllRounder")}}

classSpinPitchTeamTemplate:TeamTemplate{overridefuncpickBatsmen(){print("Picking5Batsmen")}overridefuncpickBowlers(){print("Picking2FastBowlersand2Spinners")}overridefuncpickAllRounders(){print("Picking2SpinAllRounder")}}

classBattingPitchTeamTemplate:TeamTemplate{overridefuncpickBatsmen(){print("Picking7Batsmen")}overridefuncpickBowlers(){print("Picking2FastBowlersand1Spinners")}overridefuncpickAllRounders(){print("Picking1BattingAllRounder")}}

WedefinethreetemplatesnamedSeamingPitchTeamTemplate,SpinPitchTeamTemplate,andBattingPitchTeamTemplate,withdifferentmethoddefinitionsforpickBatsmen,pickBowlers,andpickAllRounders.

Page 142: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

Letusnowwriteourmainmethodandseethecodeinaction.

funcmain(){varfinalTeam:TeamTemplate=SeamingPitchTeamTemplate()finalTeam.buildTeam()}

main()

AssumewearepickingateamforseamfriendlypitchandwetakeaninstanceofSeamingPitchTeamTemplateandcallthebuildTeammethod.

OutputintheXcodeconsole:

Picking6batsmenPicking3FastBowlersPicking1PaceAllRounderOnlyoneWKavailableandheispickedbydefault

TeamSetForthematch

Now,wechangetheteamcompositionsbytakinginstancesofothertemplatesandobservetheoutput.

funcmain(){varfinalTeam:TeamTemplate=SeamingPitchTeamTemplate()finalTeam.buildTeam()print("\n***PitchChanged***\n")finalTeam=SpinPitchTeamTemplate()finalTeam.buildTeam()}

main()

OutputintheXcodeconsole:

Page 143: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

Picking6batsmenPicking3FastBowlersPicking1PaceAllRounderOnlyoneWKavailableandheispickedbydefault

TeamSetForthematch

***PitchChanged***

Picking5BatsmenPicking2FastBowlersand2SpinnersPicking2SpinAllRounderOnlyoneWKavailableandheispickedbydefault

TeamSetForthematch

Nowchangethemainmethodto:

funcmain(){varfinalTeam:TeamTemplate=SeamingPitchTeamTemplate()finalTeam.buildTeam()print("\n***PitchChanged***\n")finalTeam=SpinPitchTeamTemplate()finalTeam.buildTeam()print("\n***PitchChanged***\n")finalTeam=BattingPitchTeamTemplate()finalTeam.buildTeam()}

main()

OutputintheXcodeconsole:

Picking6batsmenPicking3FastBowlersPicking1PaceAllRounder

Page 144: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

OnlyoneWKavailableandheispickedbydefault

TeamSetForthematch

***PitchChanged***

Picking5BatsmenPicking2FastBowlersand2SpinnersPicking2SpinAllRounderOnlyoneWKavailableandheispickedbydefault

TeamSetForthematch

***PitchChanged***

Picking7BatsmenPicking2FastBowlersand1SpinnersPicking1BattingAllRounderOnlyoneWKavailableandheispickedbydefault

TeamSetForthematch

Summary:

Whenyouareinasituationtobuildatemplate/baseclass,whichisopenforextensionbutclosedformodification,orinsimplewords,subclassesshouldbeabletoextendthebasealgorithmwithoutalteringitsstructure,Templatedesignpatternsuitsthebest.

Page 145: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

28)Behavioural-VisitorDesignPatternDefinition:

Visitorisabehaviouraldesignpatternthatletsusdefineanewoperationwithoutchangingtheclassesoftheobjectsonwhichitoperates.Weuseitwhenwedonotwanttokeepmodifyingeveryclassinthehierarchy.

Usage:

Considerasituationwherewearedesigningacheck-outcounterinashopthatsellscricketaccessories.Itoffersdiscountsonselectivebrandsandselectiveitems.LetusseehowwecanuseVisitorpatterntodesignsuchasystem.

importFoundationimportUIKit

protocolCricketAccessory{funcaccept(counter:CheckoutCounter)->Int}

WedefineaprotocolcalledCricketAccessorywithafunctioncalledaccept,whichtakesaparameteroftypeCheckoutCounter(tobedefined)andreturnsaninteger.

classCricketBat:CricketAccessory{privatevarprice:Doubleprivatevarbrand:Stringinit(_price:Double,_brand:String){

Page 146: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

self.price=priceself.brand=brand}publicfuncgetPrice()->Double{returnprice}publicfuncgetBrand()->String{returnbrand}funcaccept(counter:CheckoutCounter)->Int{returncounter.moveToCounter(bat:self)}}

WethendefineaclasscalledCricketBatconformingtoCricketAccessoryprotocol.Ithastwoprivatevariablesdefined:priceoftypeDoubleandbrandoftypeString.WealsodefinetwopublicmethodscalledgetPriceandgetBrandtoreturnpriceandbrandofthebatrespectively.

classCricketBall:CricketAccessory{

privatevartype:Stringprivatevarprice:Double

init(_type:String,_price:Double){self.type=typeself.price=price

}

publicfuncgetType()->String{returntype}

publicfuncgetPrice()->Double{returnprice}

Page 147: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

funcaccept(counter:CheckoutCounter)->Int{returncounter.moveToCounter(ball:self)}

}

WedefineanotherclasscalledCricketBallconformingtoCricketAccessoryprotocol.ThisisverymuchsimilartoCricketBatclass.

protocolCheckoutCounter{funcmoveToCounter(bat:CricketBat)->IntfuncmoveToCounter(ball:CricketBall)->Int}

WedefineaprotocolcalledCheckoutCounter,whichhastwomethodswiththesamenamebutdifferswhenitcomestoparametertypes.classCashCounter:CheckoutCounter{funcmoveToCounter(bat:CricketBat)->Int{varcost:Int=0ifbat.getBrand()=="MRF"{cost=Int(0.9*bat.getPrice())}else{cost=Int(bat.getPrice())}print("Batbrand:\(bat.getBrand())andpriceis:\(cost)")returncost}

funcmoveToCounter(ball:CricketBall)->Int{print("BallType:\(ball.getType())andpriceis:\(ball.getPrice())")returnInt(ball.getPrice())}}

WenowdefineaclasscalledCashCounterconformingtoCheckoutCounter.Wecanseethat,foracricketbatofbrandMRF,wegiveadiscountof10%.Inthefuture,ifwewanttoaddanynewbrandsorremovediscountsonexisting

Page 148: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

brands,wecanmakeallthechangesherewithnochangesrequiredattheclientend.Letusnowwriteamainfunctiontoseethecodeinaction.funcmain(){print("Main")funcfinalPriceCalculation(accessories:[CricketAccessory])->Int{varcheckout=CashCounter()varcost=0foriteminaccessories{cost+=item.accept(counter:checkout)}print("Totalcartvalue:\(cost)")returncost}varcartItems=[CricketAccessory]()letmrfBat=CricketBat(2000,"MRF")letbrittaniaBat=CricketBat(1500,"Brittania")lettennisBall=CricketBall("Tennis",120)letleatherBall=CricketBall("Leather",200)cartItems.append(mrfBat)cartItems.append(brittaniaBat)cartItems.append(tennisBall)cartItems.append(leatherBall)

varcost=finalPriceCalculation(accessories:cartItems)print("CheckedOutwithBillAmount:\(cost)")}

main()

WedefineafunctioncalledfinalPriceCalculation,whichtakesanarrayoftypeCricketAccessoryandreturnsthefinalcartvalue.

OutputintheXcodeconsole:

MainBatbrand:MRFandpriceis:1800Batbrand:Brittaniaandpriceis:1500

Page 149: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

BallType:Tennisandpriceis:120.0BallType:Leatherandpriceis:200.0Totalcartvalue:3620CheckedOutwithBillAmount:3620

YoucanseetheMRFbatischeckedoutatdiscountedprice.

LetusnowchangetheCashCounterclasstothefollowing:

classCashCounter:CheckoutCounter{funcmoveToCounter(bat:CricketBat)->Int{varcost:Int=0ifbat.getBrand()=="Brittania"{cost=Int(0.8*bat.getPrice())}else{cost=Int(bat.getPrice())}print("Batbrand:\(bat.getBrand())andpriceis:\(cost)")returncost}

funcmoveToCounter(ball:CricketBall)->Int{print("BallType:\(ball.getType())andpriceis:\(ball.getPrice())")returnInt(ball.getPrice())}}

Now,weareremovingthediscountonMRFandgivinga20%discountonBrittaniabats.

ThesamemainmethodgivesadifferentoutputintheXcodeconsole:

MainBatbrand:MRFandpriceis:2000Batbrand:Brittaniaandpriceis:1200BallType:Tennisandpriceis:120.0BallType:Leatherandpriceis:200.0Totalcartvalue:3520

Page 150: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

CheckedOutwithBillAmount:3520

Summary:

Whenyouareinasituationwhereyoumightwanttoaddanewactionandhavethatnewactionentirelydefinedwithinoneofthevisitorclassesratherthanspreadoutacrossmultipleclasses,Visitordesignpatternservesyouthebest.

Page 151: Design Patterns in Swift: A Different Approach to Coding ...englishonlineclub.com/pdf/Design Patterns in Swift... · 1. SOLID - Single Responsibility Principle 2. SOLID - Open Closed

Finalnote:

Finalnote:

Itisnotnecessarytolearnallthepatternsandtheirapplicationsbyheart.Themainintentionistoidentifytheusecasesandproblems,whichthedesignpatternsaremeanttoaddress.Thenapplyingaspecificdesignpatternisjustamatterofusingtherighttoolattherighttimefortherightjob.It'sthejobthatmustbeidentifiedandunderstoodbeforethetoolcanbechosen.

HappyCoding!!!