Go 实现装饰器
类似于 Java 中的装饰器模式, 在 go 中也会有需要 patch 一个函数的需求.
一个常见的场景就是比如计算某个函数耗时的 decorator, 那么利用 functional programming 思想. 在 go 中的实现如下:
1
2
3
4
5
6
7
8
|
func timeSpent(inner func(n int) int) func(op int) int {
return func(n int){
start := time.Now()
ret := inner(n)
fmt.Println("time spent: ", time.Since(start).Seconds())
return ret
}
}
|
当然实际场景中可能更多需要的是一种 pipeline 装饰器的用法, 比如一个 http handler 需要进行 Auth 认证, 认证通过后需要进行耗时计算, 计算完耗时需要进行 statsd 打点. 那么对应的实现如下:
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
|
func StatsdTiming() func(http.handler) http.Handler {
return func(next http.Handler) http.Hanlder {
fn := func(w http.ResponseWriter, r *http.Request) {
lbSpanTime := time.Duration(0)
if parsed, err := strconv.ParseFloat(r.Header.Get("X-Request-Start"), 64); err == nil {
sec := int64(parsed)
nsec := int64((parsed - float64(sec)) * 1000000000)
lbStartTime := time.Unix(sec, nsec)
lbSpanTime = time.Now().Sub(lbStartTime)
statsdClient.TimingDuration(fmt.Sprintf("reqtime", lbSpanTime))
}
}
}
}
func Auth() func(http.handler) http.Handler {
return func(next http.Handler) http.Hanlder {
function_name_str := runtime.FuncForPC(reflect.ValueOf(input).Pointer()).Name()
function_name_array := strings.Split(function_name_str, "/")
module_method := strings.Split(function_name_array[len(function_name_array)-1], ".")
module := module_method[0]
method := module_method[1]
if module != "Login" {
abort("Not Auth")
}
}
}
http.HandleFunc("/hello", Handler(hello,
Auth, StatsdTiming))
|