装饰器
装饰器(decorator)是一个这样的函数:它的参数是具体类型的函数,并且返回值也是和参数相同类型的函数。 看下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 type StringOperator func (string ) string func ident (s string ) string { return s } func ToUpper (m StringOperator) StringOperator { return func (s string ) string { lower := strings.ToUpper(s) return m(lower) } } func ToMd5 (m StringOperator) StringOperator { return func (s string ) string { h := md5.New() h.Write([]byte (s)) b64 := base64.StdEncoding.EncodeToString(h.Sum(nil )) return m(b64) } }
ToUpper
和ToMd5
都接受func(string) string
作为参数,并且返回和参数相同的类型func(string) string
。 调用情况:
1 2 3 4 5 6 7 8 9 10 11 func TestDecorator1 (t *testing.T) { s := "Hello, World" var fn1 StringOperator = ident fn1 = ToMd5(ToUpper(ident)) fmt.Println(fn1(s)) var fn2 StringOperator = ident fn2 = ToUpper(ToMd5(fn2)) fmt.Println(fn2(s)) }
net/http
的http.HandleFunc
也用到了装饰器模式。
1 type HandlerFunc func (ResponseWriter, *Request)
调用者可以自己设置http的调用链。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func hello (w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, World! " +r.URL.Path) } func WithLog (h http.HandlerFunc) http .HandlerFunc { return func (w http.ResponseWriter, r *http.Request) { log.Printf("Recieved Request %s from %s\n" , r.URL.Path, r.RemoteAddr) h(w, r) } } func TestHttp (t *testing.T) { http.HandleFunc("/hello" , WithLog(hello)) err := http.ListenAndServe(":8080" , nil ) if err != nil { log.Fatal("ListenAndServe: " , err) } }
装饰器的流水线(Pipeline) 有时候,多层的调用可能会导致代码不好阅读,例如ToMd5(ToUpper(ident))
。这时候可以改成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 type Decorator func (StringOperator) StringOperator func Handler (m StringOperator, decorators ...Decorator) StringOperator { for i := len (decorators) - 1 ; i > 0 ; i-- { m = decorators[i](m) } return m } func TestDecorator (t *testing.T) { s := "Hello, World" fn := Handler(ident, ToUpper, ToMd5) fmt.Println(fn(s)) }
设置默认参数 Golang
中,函数不支持设置默认参数,可以使用类似装饰器的方法来设置。 看下面的例子,通过WithNum
和WithString
来指定参数。
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 type Param struct { p1 int p2 OptionParam } type OptionParam struct { a int b string } func defaultOptionParam () OptionParam { option := OptionParam{ a: 10 , b: "const" , } return option } type SetOption func (option *OptionParam) func WithNum (num int ) SetOption { return func (option *OptionParam) { option.a = num } } func WithString (str string ) SetOption { return func (option *OptionParam) { option.b = str } } func SetParams (p1 int , setOptions ...SetOption) Param { option := defaultOptionParam() for _, set := range setOptions { set(&option) } return Param{ p1: p1, p2: option, } }
我的公众号:lyp_share
我的知乎专栏
我的博客com
我的博客cn