动用 装饰器模式 写控制逻辑从简单--->pipeline装饰

355 阅读2分钟

1 简单的装饰器模式

func decorator(f func(s string)) func(s string) {
	return func(s string) {
		fmt.Println("Started")
		f(s)
		fmt.Println("Ended")
	}
}

func Hello(s string){
	fmt.Printf(s)
}

// 简单的装饰器模式

func main(){
	decorator(Hello)("Hello, world!\n")
}

2 简单的装饰器模式(接口化)

type SumFunc func(int64, int64) int64

func getFunctionName(i interface{}) string {
	return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}

func timedSumFunc(f SumFunc) SumFunc {
	return func(start, end int64) int64 {
		defer func(t time.Time) {
			fmt.Printf("--- Time Elapsed (%s): %v ---\n", getFunctionName(f), time.Since(t) )
		}(time.Now())
		return f(start, end)
	}
}

func Sum1(start, end int64) int64 {
	var sum int64
	sum = 0
	if start > end {
		start, end = end, start
	}

	for i := start; i <= end; i++ {
		sum += i
	}

	return sum
}

func Sum2(start, end int64) int64 {
	if start > end {
		start, end = end, start
	}
	return (end - start + 1) * (end + start) / 2
}

// 简单的装饰器模式(接口化)

func main(){
	sum1 := timedSumFunc(Sum1)
	sum2 := timedSumFunc(Sum2)

	fmt.Printf("%d, %d\n", sum1(-10000, 10000000), sum2(-1000, 1000000))
}

3 嵌套修饰函数 -->pipeline

func WithServerHeader(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("------>WithServerHeader()")
		w.Header().Set("Server", "HelloServer v0.0.1")
		h(w, r)
	}
}

func WithAuthCookie(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request){
		log.Println("---->WithAuthCookie()")
		cookie := &http.Cookie{Name: "Auth", Value: "Pass", Path: "/"}
		http.SetCookie(w, cookie)
		h(w, r)
	}
}

func WithDebugLog(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("---->WithDebuglog")
		r.ParseForm()
		log.Println(r.Form)
		log.Println("path", r.URL.Path)
		log.Println("scheme", r.URL.Scheme)
		log.Println(r.Form["url_long"])

		for k,v := range r.Form {
			log.Println("key:", k)
			log.Println("val:", strings.Join(v, ""))
		}
		h(w, r)
	}
}

func WithBasicAuth(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r * http.Request) {
		log.Println("---> WithBasicAuth()")
		cookie, err := r.Cookie("Auth")
		if err != nil  || cookie.Value != "Pass" {
			w.WriteHeader(http.StatusForbidden)
			return
		}
		h(w, r)
	}
}

func hello(w http.ResponseWriter, r *http.Request) {
	log.Printf("Received Request %s from %s\n", r.URL.Path, r.RemoteAddr)
	fmt.Fprintf(w, "Hello, world!" + r.URL.Path)
}

// 嵌套修饰函数

func main() {
	http.HandleFunc("/v1/hello", WithServerHeader(WithAuthCookie(hello)))
	http.HandleFunc("/v2/hello", WithServerHeader(WithBasicAuth(hello)))
	http.HandleFunc("/v3/hello", WithServerHeader(WithBasicAuth(WithDebugLog(hello))))
	http.HandleFunc("/v4/hello", WithServerHeader(WithBasicAuth(WithDebugLog(WithAuthCookie(hello)))))
	http.HandleFunc("/v5/hello", Handler(hello, WithServerHeader, WithBasicAuth, WithDebugLog))

	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal("ListenAndServer:", err)
	}
}


// 定义接口

type HttpHandlerDecorator func(http.HandlerFunc) http.HandlerFunc

// pipeline

func Handler(h http.HandlerFunc, decors ...HttpHandlerDecorator) http.HandlerFunc {
	for i := range decors {
		d := decors[len(decors) - i - 1] // 逆序
		h = d(h)
	}
	return h
}

4 小结

  1. 修饰器模式就是扩展现有的一个函数的功能,让它可以干一些其他的事,或是在现有的函数功能上再附加上一些别的功能。
  2. 函数式编程下的代码扩展能力-:::::-->函数互相和随意拼装.
  3. 容易将一些非业务功能的、属于控制类型的代码给抽象出来( for-loop,打日志,函数路由,求函数运行时间之类非业务功能性的代码)