Instantly share code, notes, and snippets.

Embed
What would you like to do?
package main
import (
"fmt"
"log"
"os"
"sync"
"time"
)
type Adder interface {
Add(x, y int) int
}
type AdderFunc func(x, y int) int
func (a AdderFunc) Add(x, y int) int {
return a(x, y)
}
// Middleware function, this function takes in a `Adder` and returns a new `Adder`.
type AdderMiddleware func(Adder) Adder
func WrapLogger(logger *log.Logger) AdderMiddleware {
return func(a Adder) Adder {
// Using `AdderFunc` to implement the `Adder` interface.
fn := func(x, y int) (result int) {
defer func(t time.Time) {
logger.Printf("took=%v, x=%v, y=%v, result=%v", time.Since(t), x, y, result)
}(time.Now())
// Propogate call to original adder
return a.Add(x, y)
}
// Return a new `Adder` wrapped with the loggin functionality
return AdderFunc(fn)
}
}
func WrapCache(cache *sync.Map) AdderMiddleware {
return func(a Adder) Adder {
fn := func(x, y int) int {
key := fmt.Sprintf("x=%dy=%d", x, y)
val, ok := cache.Load(key)
if ok {
return val.(int)
}
result := a.Add(x, y)
cache.Store(key, result)
return result
}
return AdderFunc(fn)
}
}
func Chain(outer AdderMiddleware, middleware ...AdderMiddleware) AdderMiddleware {
return func(a Adder) Adder {
topIndex := len(middleware) - 1
for i := range middleware {
a = middleware[topIndex-i](a)
}
return outer(a)
}
}
func main() {
var a Adder = AdderFunc(
func(x, y int) int {
return x + y
},
)
a = Chain(
WrapLogger(log.New(os.Stdout, "test ", 1)),
WrapCache(&sync.Map{}),
)(a)
a.Add(10, 20)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment