Go Design Patterns - The Decorator Pattern - Part One
Skills:
LLM Engineering80%Tool Use & Function Calling80%Prompt Systems Engineering70%Prompt Craft60%Agent Foundations50%
Key Takeaways
The Decorator Pattern in Go is used to build composite functions and create middleware, demonstrated through logging and caching functionalities. The tutorial covers defining decorator functions, chaining multiple decorators, and applying them to functions using Go and its libraries.
Full Transcript
hi guys my name is tensor welcome to the go design pattern tutorial series in today's video we're going to talk about the decorator pattern some of you may have heard this term decorator before and you may have even used it in other programming languages such as Python Java and typescript and of course you can use decorators in go now decorators essentially allow you to wrap existing functionality and then inject your own custom functionality on top of that functionality and we're able to get away with this because functions in go are first-class which means that we can pass functions to variables we can pass functions to other functions and we can of course return functions from functions to demonstrate the decorator pattern I've created a function here called pi this function just takes in a value and then it uses that value to approximate the number of pi so we create a channel of float64 here and then we iterate from 0 to n which is the number that we're passing in here and the higher this number is the better our approximation will be for each iteration will spawn a new go routine on this anonymous function here and the anonymous function will take in our channel and it will take in our K value as a float64 and it will run this calculation and then pass it into the channel now down here we have our result variable which will start at 0 0 then we'll iterate again from 0 all the way up to N and we'll take all of the values from our channel and then just increment our result with them after we're done cleaning out all of the values from the channel we'll go ahead and return this result from this function so I'm going to call fmt println pi with 1000 inside of it and then I'm going to call it also with 50000 inside of it and we'll see the approximations of pi so here you can see that our top approximate gave us three point one four to five and then our bottom approximation is a bit more accurate giving us three point one four one now let's say we want to take this function and wrap it inside of a lager in such a way that the lager will tell us how long it took to execute the function well to accomplish this we can go ahead and use what's called a decorator function now to start out we can create a function called wrap lager and this will take in a function that takes in an integer and a float 64 which is the type of our PI function down here and then it will return that same type of function and actually to make this easier to read we can alias this function type as pi func and then just replace these declarations so this wrap lager function will take in a PI funk which is just a function that takes in an int and returns a float 64 and then it will return a PI func type while we're at it let's also add a lager variable here which will take in a reference to log lager which will allow us to specify how we want our lager to actually function so then inside of this function will return an anonymous function that takes in an integer and returns a float 64 and in the body of this function we can then create our lager and also execute the PI function and notice that we can just take the function that we're passing in to wrap logger and just call it on N and this in essence would just give us our PI function back except it would also have the logger scoped to it as well the body of this function is going to get a tad more complicated when we add the actual logger because we want this logger to execute as soon as our function starts and also when the function ends and we can accomplish this by using the defer keyword and then creating yet another as function our inner anonymous function is where we're getting the timestamp for when the function execution starts this takes in a value of time time and the value is being passed in here so this is being executed immediately with time dot now as the argument but because it's being deferred this will not complete execution until the end of this outer function body because it's being called down here inside of it we're calling lager print F we're putting in that it took a time sense value which is just a time comparison between time now and then the current time so this will give us the amount of time that it took to execute the function then we can see the value n that we passed in and then we can also see the result and this result value is why we have this second anonymous function being wrapped around the defer call so you can see here that the second anonymous function takes in a value and int and then it also returns a float 64 but because we want to access that return value we named it as a result and what that does is it allows us to gain access to the return value of our function in this closure and then we can use it in our logger here in this FN function that we're creating we'll call fun which is the argument function that we're passing in here which will be our PI function so this will start the execution of our PI function and then outside of the FN declaration we call f n with n once we define this decorator function we can now go down to our main function and just call it and we call it on our PI function and then we pass in the augur that we want to add and this is just a call to log new with OS standard out because we want it to print to our console and then we want it to start with the word test this will give us back a function which we can invoke with the value that we want to pass into our PI function so here I'm passing in 100,000 and then this will go through our lager and our PI function and we'll have all of this behavior attached to this new composite function we can see when we go ahead and run this that we get that it took 660 milliseconds with an 100000 and the result was three point one four one six zero two etc this decorator pattern is especially useful when you want to create middleware for like a server or a client or a sort of like restful api and in fact the HTTP library ingo uses the decorator pattern quite a lot now let's say we want to add a second decorator currently we have the logger decorator and this gives us a new function and we can chain it together with another decorator to add more functionality to our PI function if we wanted to say call PI 100,000 and then call it again we would have to go through both executions and so it makes sense to create a cache decorator function so to create the cache function we'll create a function called wrap cache this will take in a PI func type and then our cache which will be a sync map type and this is just a map primitive that is thread safe and the reason why we want to use this primitive is because our PI function is using a lot of go routines and then like our wrap logger function our wrap cache function will also return a PI func type inside of our cast function will again return a function that takes in an integer and a float 64 and will again create another anonymous function that also takes in an integer in a float at 64 will first define the key that we want to add to our map so this will be the key that were and we can use fmt s printf pass in the value end and put it into a string of N equals with the N number inside of it then we can call to our cash and we can call load on our key to check to see if that key is already populated in our sync map and this will return the value and then a boolean and if this boolean comes back as true then we want to return this value as a float64 otherwise we want to continue call our function our PI func on n get the result and then store that result inside of our cache map with the key and then return the result from this function and then of course because we need to return a float 64 from this anonymous function will call this FN function on n every turn it and now we can come down to our main function call wrap cash on PI and then pass in a reference to the sync map that we want to use as our cash and then take that function f and call wrap logger on it which will give us a function G which we can then call and this function G will have both our cash and or logger behavior on top of our PI function first when we run it with 100,000 the time it takes is 706 milliseconds then we run it on say 20,000 and it takes 66 milliseconds and then again when we run it on 100,000 it takes 0 seconds because it gets the value from the cache one thing that you want to keep in mind with this current implementation is that you want to wrap the cache on top of PI first and then wrap the logger on top of both of those functions if you don't do that then the cache function if it returns a value will not actually put that value into the logger and to kind of explain this let's take a look at the actual structure of our functions so we have PI in the middle then we have logger and then we have cat so when we call rap cash the fun function here is a combination of the lager and the pie function when we come to this if statement we return the value with type float64 but we never actually execute the fun function which means that we don't actually execute the lager either and so this return value just gets returned from our function but it doesn't actually go into our lager if however we have the lager on the outside then it doesn't really matter if we get a value returned in that way or if we get a value return by invoking the pie function one of the cooler features of the decorator pattern is that you can reuse all of the decorators many times over many different objects so long as those objects follow the same pattern so this divided function which I've created here which is pretty simple it just takes a number which is an integer and then divides it by two and then cast that value as a float 64 follows the same type declaration as our PI function and so this divide function can also be wrapped inside of the cash function and our logger function so instead of passing in PI we pass in divide and then we wrap the value here F in the wrap logger which then gives us this function G and we can of course call it with different values and now you can see that we get back the calculations of Pi and then we also get back in the division calculations so so long as the function follows this type declaration we can attach all of these decorators to it and this is a very flexible idea because you can really create a ton of different functions which can follow these types of patterns and also because of the way that we're composing all of these functions together the main functions do not actually care about how the decorators are structured and vice versa so our rap cache decorator just deals with the cash and our rap logger decorator just deals with the logger and only they know how the implementation of the cache are the logger actually is whereas the divide and the pie functions don't really care what that implementation is and so even if I radically changed rap cache and rap logger so long as the general pattern is held they should still work on these functions alright guys well I hope you enjoyed this tutorial if you did feel free to like and subscribe if you have any questions or comments feel free to leave them in the box below and if you dislike this video then by all means download it as much as you like if you want to catch more videos on go design patterns then I recommend you click on the notification bell have a good night
Original Description
#tensorprogramming #golang #designpatterns
In this tutorial, we take a look at the decorator pattern in Go. We use it to build composite functions and create middleware that can be plugged into any like function or type.
Source Code: https://github.com/tensor-programming/pattern-tutorial/blob/master/decorator/main.go
Request Form: https://goo.gl/forms/rFjHcZMRJ3bYPEC03
Cloudways Web App Hosting: https://www.cloudways.com/en/?id=507366
Support the Channel and Join Patreon:
Patreon: https://www.patreon.com/tensor_programming
Dontate:
ETH: 0x03247265dd5242605bD2FA3c40fb3b70d9e3D685
Cardano: addr1q9auccwrr9ws8qdyv45f4qwsx76pfmld4zapks89sakq94ay0xmle73y0r8ruwd0zslls4eglf98lghru7ywv56cedysk7ftjt
Check out our Twitter: https://twitter.com/TensorProgram
Check out our Facebook: https://www.facebook.com/Tensor-Programming-1197847143611799/
Check out our Steemit: https://steemit.com/@tensor
Watch on YouTube ↗
(saves to browser)
Sign in to unlock AI tutor explanation · ⚡30
Playlist
Uploads from Tensor Programming · Tensor Programming · 0 of 60
← Previous
Next →
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
NodeJs, Text editors and IDEs
Tensor Programming
Vanilla JS todo App
Tensor Programming
Elm Tutorial part 1
Tensor Programming
Elm Lang Tutorial, Part 2
Tensor Programming
Elm Tutorial Part 3
Tensor Programming
Elm Tutorial Part 4 -- Analog Clock App
Tensor Programming
Elm Tutorial part 5 -- Snake Game
Tensor Programming
Elm Tutorial part 6 -- Calculator
Tensor Programming
Go Tutorial part 1 -- Hello World and Static File Server
Tensor Programming
Go Tutorial part 2 -- Web Crawler
Tensor Programming
Go Tutorial Part 3 (Web App part 1)
Tensor Programming
Go tutorial Part 4 (Web tutorial part 2) - Using templates
Tensor Programming
Go tutorial part 5 (web app part 3)
Tensor Programming
Go tutorial part 6 (webapp part 4)
Tensor Programming
Go tutorial part 7 (web app part 5)
Tensor Programming
Go tutorial part 8 (Web app part 6)
Tensor Programming
Go tutorial Part 9 (web tutorial part 7)
Tensor Programming
Go tutorial Part 10 (web app part 8)
Tensor Programming
Go tutorial Part 11 (Web app Part 9)
Tensor Programming
Go Tutorial Part 12 (Web app Part 10)
Tensor Programming
Go Tutorial Part 13 (Web app Part 11)
Tensor Programming
Looking at Elm 0.18
Tensor Programming
Go tutorial Part 14 (Web tutorial part 12)
Tensor Programming
Go tutorial Part 15 (Web tutorial part 13)
Tensor Programming
Go tutorial part 16 (web app part 14)
Tensor Programming
Elm Tutorial Part 7 (SPA part 1)
Tensor Programming
Elm Tutorial Part 8 (SPA Part 2)
Tensor Programming
Electron Elm Tutorial
Tensor Programming
Go tutorial part 17 (web app part 15)
Tensor Programming
Up and Coming Programming Languages and Technologies for 2017
Tensor Programming
elixir tutorial part 1
Tensor Programming
elixir tutorial part 2
Tensor Programming
Elixir tutorial Part 3 (GenServer and Supervisor)
Tensor Programming
Elixir Tutorial Part 4 (GenStage)
Tensor Programming
Elixir Tutorial Part 5 (Plug and Cowboy)
Tensor Programming
Phoenix Framework Tutorial Part 1 (elixir part 6)
Tensor Programming
Phoenix Framework Tutorial Part 2 (elixir part 7)
Tensor Programming
Phoenix Framework Tutorial Part 3 (elixir part 8)
Tensor Programming
A Intro to Clojure and Clojure Syntax
Tensor Programming
An Update about the channel
Tensor Programming
Intro to Rustlang (Setup and Primitives)
Tensor Programming
Intro to Rustlang (Strings, Tuples, Arrays, Slices and Pretty Printing)
Tensor Programming
Intro to Rustlang (Ownership and Borrowing)
Tensor Programming
Intro to Rustlang (Structs, Methods, Functions, Related Functions and the Display/Debug Traits)
Tensor Programming
Intro to Rustlang (Control Flow, Conditionals and Pattern Matching)
Tensor Programming
Intro to RustLang (Enums and Options)
Tensor Programming
Intro to Rustlang (Vectors, HashMaps, Casting, If-Let, While-Let, and the Result Enum)
Tensor Programming
Rustlang Project: Snake Game
Tensor Programming
Intro to Rustlang (Traits and Generic Types)
Tensor Programming
Intro to Rust-lang (Closures, the Box Pointer and Iterators)
Tensor Programming
Intro to Rust-lang (Modules and Lifetimes)
Tensor Programming
Intro to Rust-lang (Macros and Metaprogramming)
Tensor Programming
Intro to Rust-lang (Error Handling)
Tensor Programming
Intro to Rust-lang (Concurrency, Threads, Channels, Mutex and Arc)
Tensor Programming
Intro to Rust-lang (Tests, Attributes, Configuration and Conditional compilation)
Tensor Programming
Rustlang Project: Port Sniffer CLI
Tensor Programming
Rustlang Project: Chat Application
Tensor Programming
Rustlang Project: CLI Toy Blockchain
Tensor Programming
Intro to Rust-lang (Setting up a Development Environment)
Tensor Programming
Intro to Rust-lang (Building a Web API with Iron)
Tensor Programming
More on: LLM Engineering
View skill →Related Reads
📰
📰
📰
📰
InsForge vs Firebase: AI-Native Postgres Alternative
Dev.to AI
InsForge vs Supabase: AI-Native Backend Alternative
Dev.to AI
A model rated a visibly wrong red 0.97 on-brand. That number changed what I built.
Medium · AI
Best AI Appointment Setter Software in 2026: 11 Tools Compared
Medium · AI
🎓
Tutor Explanation
DeepCamp AI