Reacting to File Changes Using the Observer Design Pattern ...
文章推薦指數: 80 %
To illustrate the observer pattern in Go, we are going to watch for changes in a local folder. Every time a folder or a file is created, ... Sciencehasshownthatshypeoplearecleverbecausetheyspendmoretimelisteningandobservingandlesstimespeakingandshowingoff.Theyabsorbmoreinformationandspendcountlesshoursreasoningthem.Theydoitquietlyandarerarelyrecognizedbytheirintellects.WhatsciencehasnotshownisthattheObserverDesignPatternisalsoahumblepartofacrafteddesignedsoftwarebutrarelyrecognizedaswell. Youknowyouareinfrontofaobserverimplementationwhenaneventhappensandoneormultipleroutinesreacttothat.Thesourceoftheeventisnormallycalledpublisherandthecodethatreactstothatiscalledsubscriber.Youcanactuallyhaveapropagationofeventswheresubscribersalsoactaspublishers,triggeringothersubscribersinachainreaction.Thesetwoconceptsarealsopopularinmessagingsystems,whichisawaytoimplementtheobserverpatterninadistributedanddecoupledfashion. ToillustratetheobserverpatterninGo,wearegoingtowatchforchangesinalocalfolder.Everytimeafolderorafileiscreated,modified,orremoved,aneventispublishedandpropagatedtosubscribers.Towatchthelocalfilesystemwerelyonfsnotify.Whensomethinghappens,wegeteventsfromfsnotifyandpropagetheeventtooursubscribers.ThefullimplementationisavailableinmyGithubrepo.Let’sreviewit,startingwithtwointerfaces: typePublisherinterface{ register(subscriber*Subscriber) unregister(subscriber*Subscriber) notify(path,eventstring) observe() } typeSubscriberinterface{ receive(path,eventstring) } ThePublisherinterfacerequirestheimplementertoregister()andunregister()subscribers,andnotify()subscribersaboutevents.Theobserve()behaviourisspecificforthiscasebecausethepublisherisalsoasubscriberoffsnotifyevents.Tobehonest,thePublisherinterfaceisnotreallynecessarybut,aswesawinthearticleabouttheadapterdesignpattern,ithelpstoencapsulatethefsnotifylibrary. TheSubscriberinterfaceissimpler,pushingtheimplementationofareceive()methodthatgetsthemessagefromthepublisher.Let’sfirstlookatthePublisherimplementation:thePathWatcherstruct. //PathWatcherobserveschangesinthefilesystemandworksasaPublisherfor //theapplicationbynotifyingsubscribers,whichwillperformotheroperations. typePathWatcherstruct{ subscribers[]*Subscriber watcherfsnotify.Watcher rootPathstring } //registersubscriberstothepublisher func(pw*PathWatcher)register(subscriber*Subscriber){ pw.subscribers=append(pw.subscribers,subscriber) } //unregistersubscribersfromthepublisher func(pw*PathWatcher)unregister(subscriber*Subscriber){ length:=len(pw.subscribers) fori,sub:=rangepw.subscribers{ ifsub==subscriber{ pw.subscribers[i]=pw.subscribers[length-1] pw.subscribers=pw.subscribers[:length-1] break } } } //notifysubscribersthataeventhashappened,passingthepathandthetype //ofeventasmessage. func(pw*PathWatcher)notify(path,eventstring){ for_,sub:=rangepw.subscribers{ (*sub).receive(path,event) } } //observechangestothefilesystemusingthefsnotifylibrary func(pw*PathWatcher)observe(){ watcher,err:=fsnotify.NewWatcher() iferr!=nil{ fmt.Println("Error",err) } deferwatcher.Close() iferr:=filepath.Walk(pw.rootPath, func(pathstring,infoos.FileInfo,errerror)error{ ifinfo.Mode().IsDir(){ returnwatcher.Add(path) } returnnil });err!=nil{ fmt.Println("ERROR",err) } done:=make(chanbool) gofunc(){ for{ select{ caseevent:=post.txt $rmpost.txt Liftboxproducesthefollowingoutput: Indexing:/home/htmfilho/liftbox/pictures,CREATE Checksuming:/home/htmfilho/liftbox/pictures,CREATE Indexing:/home/htmfilho/liftbox/post.txt,CREATE Checksuming:/home/htmfilho/liftbox/post.txt,CREATE Indexing:/home/htmfilho/liftbox/post.txt,WRITE Checksuming:/home/htmfilho/liftbox/post.txt,WRITE Indexing:/home/htmfilho/liftbox/post.txt,REMOVE Checksuming:/home/htmfilho/liftbox/post.txt,REMOVE ThisexperienceofrevisitingthedesignpatternsinGohasbeenanamazingexperiencesofar.Thechallengeistocomeupwithideastodescribethemthroughrealisticusecases.ItakethischallengewithpleasurebecauseitisreallycooltoseeusefulcasesmaterializedinGo. «ProvisioningAzureFunctionsUsingTerraform DealingWithPressureOutsideoftheWorkplace» RecentPosts Jul17,2021 AstonishingCarlSagan'sPredictionsPublishedin1995 Apr11,2021 MakingaConfigurableGoApp Mar21,2021 DealingWithPressureOutsideoftheWorkplace Mar7,2021 ProvisioningAzureFunctionsUsingTerraform Feb28,2021 TakingAdvantageoftheAdapterDesignPattern Feb21,2021 ApplyingTheAdapterDesignPatternToDecoupleLibrariesFromGoApps Feb14,2021 UsingGoroutinestoSearchPricesinParallel Feb9,2021 ApplyingtheStrategyPatterntoGetPricesfromDifferentSourcesinGo Jan21,2021 DeployinganAzureFunctioninGo Jan17,2021 DevelopinganAzureFunctioninGo Dec25,2020 GoasaBusinessLanguage Dec21,2020 TableVersioningWithLiquibase Dec6,2020 Go:UglyandBoringfortheGoodofSoftware Dec5,2020 TheAnxiousNewcomer
延伸文章資訊
- 1Observer Pattern In Golang - Medium
Observer Pattern In Golang · The What · subscriber and the website publishes notifications only f...
- 2Go observer pattern example - gist GitHub
Go observer pattern example. GitHub Gist: instantly share code, notes, and snippets.
- 3Observer Design Pattern in Go (Golang)
Observer Design Pattern is a behavioral design pattern. This pattern allows an instance (called s...
- 4The Observer Pattern In Go - Level Up Coding
The Observer Pattern In Go ... A fundamental design pattern every software engineer needs to know...
- 5design-pattern-golang/observer.go at master - GitHub
package observer. import "fmt". type Subject struct {. observers []Observer. context string. } fu...