Sling Academy
Home/Golang/Implementing Decorators with Functions in Go

Implementing Decorators with Functions in Go

Last updated: November 26, 2024

In this article, we'll explore how to implement decorators using functions in Go. Decorators are a powerful design pattern that allow you to modify the behavior of a function at runtime without altering the function's source code. They are commonly used for logging, authentication, and other cross-cutting concerns.

Understanding Decorators

A decorator typically takes a function as an argument, adds some functionality, and returns a new function that encompasses the original function's capabilities along with the added behavior.

Creating a Simple Decorator

Let's start by creating a basic decorator in Go. We'll create a simple decorator function that logs the execution time of the target function.

package main

import (
    "fmt"
    "time"
)

func main() {
    exampleFunc := Decorate(OriginalFunction)
    result := exampleFunc("Go")
    fmt.Println(result)
}

func OriginalFunction(name string) string {
    return "Hello, " + name + "!"
}

func Decorate(fn func(string) string) func(string) string {
    return func(name string) string {
        start := time.Now()
        result := fn(name)
        duration := time.Since(start)
        fmt.Printf("Function executed in %v\n", duration)
        return result
    }
}

In this example, we define a basic function, OriginalFunction, that simply returns a greeting message. The Decorate function accepts OriginalFunction as an argument and returns a new function that measures and prints the execution time before calling the original function.

Leveraging Decorators for Multiple Concerns

Once you understand the basic principles, you can use decorators to tackle larger, more complex concerns like authentication. Here’s how you might implement a decorator for user authentication.

package main

import "fmt"

type User struct {
    Username string
    IsAuthenticated bool
}

func main() {
    user := User{Username: "john_doe", IsAuthenticated: true}
    authenticatedFunc := Authenticate(ProtectedFunction)
    authenticatedFunc(user)
}

func ProtectedFunction(user User) {
    fmt.Printf("Access granted to %s\n", user.Username)
}

func Authenticate(fn func(User)) func(User) {
    return func(user User) {
        if user.IsAuthenticated {
            fn(user)
        } else {
            fmt.Println("Access denied")
        }
    }
}

In this scenario, we have a User struct with an IsAuthenticated field. The Authenticate decorator checks if the user is authenticated before executing the ProtectedFunction function, denying access otherwise.

Conclusion

Go doesn’t support decorators as a first-class feature like some other languages, but with a creative approach using higher-order functions, one can implement similar functionality. Decorators in Go can greatly enhance the modularity and readability of your code, proving especially effective in cases involving reusable code modifications such as logging or access control.

Next Article: Using Functions to Define State Machines in Go Applications

Previous Article: Dynamic Argument Parsing in Variadic Functions for Advanced Use Cases

Series: Functions in Go

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant