沈阳工程建设信息网站电气监理,宁波抖音seo公司,企业网站建设套餐 网络服务,上海哪家公司可以做网站前言
我一直以来对golang的装饰器模式情有独衷#xff0c;不是因为它酷#xff0c;而是它带给我了太多的好处。首先我不想说太多的概念#xff0c;熟记这些概念对我的编程来说一点用处没有。我只知道它给我带来了好处#xff0c;下面谈谈我的理解。
这种模式可以很轻松地…前言
我一直以来对golang的装饰器模式情有独衷不是因为它酷而是它带给我了太多的好处。首先我不想说太多的概念熟记这些概念对我的编程来说一点用处没有。我只知道它给我带来了好处下面谈谈我的理解。
这种模式可以很轻松地把一些函数装配到另外一些函数上让你的代码更加简单也可以让一些“小功能型”的代码复用性更高让代码中的函数可以像乐高玩具那样自由地拼装。
重要的是你不用修改代码以前的功能对以前的功能没有影响而是动态的很方便的扩展函数的功能。下面我将举几个例子说明下
golang 的装饰器通常用interface{} 以及 anonymous functions 实现的下面我们看看实际的例子
一、interface{} 实现装饰器
type Printer interface {Print() string
}
type SimplePrinter struct {}
func (sp *SimplePrinter) Print() string {return Hello, world!
}
func BoldDecorator(p Printer) Printer {return PrinterFunc(func() string {return b p.Print() /b})
}
type PrinterFunc func() string
func (pf PrinterFunc) Print() string {return pf()
}
func main() {simplePrinter : SimplePrinter{}boldPrinter : BoldDecorator(simplePrinter)fmt.Println(simplePrinter.Print()) // Output: Hello, world!fmt.Println(boldPrinter.Print()) // Output: bHello, world!/b
} 在上面的代码中我们定义了一个Printer接口,一个 SimplePrinter 结构体实现了Print方法 我们定义了 BoldDecorator 函数接受一个Printer接口返回一个Printer接口.该函数将原来的 Print() 方法封装到一个新的方法中该方法返回的是用 b 标记括起来的相同值 这只是一个简单的例子却展示了装饰器的强大的功能。通过添加新的装饰器我们可以在运行时改变对象的行为而无需更改其原始代码。当我们需要为一个已经存在的对象添加新功能而又想保持其原始代码不变时装饰器模式就显得尤为有用。这样我们就可以避免为每一个想要添加的新功能创建新的子类。
二、Http 相关的装饰器的例子
func WithServerHeader(h http.HandlerFunc) http.HandlerFunc {return func(writer http.ResponseWriter, request *http.Request) {writer.Header().Set(server, 0.01)h(writer, request)}
}
func withServerSetCook(h http.HandlerFunc) http.HandlerFunc {return func(writer http.ResponseWriter, request *http.Request) {cookie : http.Cookie{Name: username, Value: tt}http.SetCookie(writer, cookie)h(writer, request)}
}
func WithBasicAuth(h http.HandlerFunc) http.HandlerFunc {return func(writer http.ResponseWriter, request *http.Request) {cookie, err : request.Cookie(username)if err ! nil || cookie.Value ! ee {writer.WriteHeader(http.StatusForbidden)return}h(writer, request)}
}
func WithDebugLog(h http.HandlerFunc) http.HandlerFunc {return func(writer http.ResponseWriter, request *http.Request) {request.ParseForm()log.Println(request.Form)log.Println(path, request.URL.Path)log.Println(Host, request.URL.Host)log.Println(request.Form[url_long])for k, v : range request.Form {log.Println(key:, k)log.Println(value:, v)}h(writer, request)}
}
func hello(w http.ResponseWriter, r *http.Request) {log.Printf(Recieved Request %s from %s\n, r.URL.Path, r.RemoteAddr)fmt.Fprintf(w, Hello, World! r.URL.Path)
}
func main() {http.HandleFunc(/hello/v1, WithServerHeader(hello))http.HandleFunc(/hello/v2, withServerSetCook(hello))http.HandleFunc(/hello/v3, WithBasicAuth(hello))http.HandleFunc(/hello/v4, WithDebugLog(hello))err : http.ListenAndServe(:8080, nil)if err ! nil {log.Fatal(ListenAndServe: , err)}
} 例子中 WithServerHeaderwithServerSetCookWithBasicAuth WithDebugLog 就是一个装饰器它传入一个 http.HandlerFunc 就是一个改写版本。而我们的业务hello不用修改任何功能可以呈现出一些新的功能很多人把这种模式称为middleware ,我更喜欢称为装饰器
三、多个装饰器Pipeline也是options 模式
type googleSlide struct {sreSlide *list.Listinterval int64mutex sync.Mutexk int64
}type slideVal struct {time int64req int64accept int64
}type SlideValOptions func(val *slideVal)func NewSlideval(options ...SlideValOptions) *slideVal {t : slideVal{time: time.Now().UnixNano(),}for _, option : range options {option(t)}return t
}func WithReqOption(req int64) SlideValOptions {return func(val *slideVal) {val.req req}
}func WithAcceptReqOption(accept int64) SlideValOptions {return func(val *slideVal) {val.accept accept}
}func NewGoogleSlide(interval time.Duration, k int64) *googleSlide {return googleSlide{sreSlide: list.New(),interval: interval.Nanoseconds(),k: k,}
}func (g *googleSlide) Sre() grpc.UnaryClientInterceptor {return func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {g.mutex.Lock()now : time.Now().UnixNano()front : g.sreSlide.Front()for front ! nil front.Value.(*slideVal).timeg.interval now {g.sreSlide.Remove(front)front g.sreSlide.Front()}var r, accept int64front g.sreSlide.Front()for front ! nil {t : front.Value.(*slideVal)r t.reqaccept t.acceptfront front.Next()}tail : (float64(r) - float64(g.k*accept)) / (float64(r) 1)if tail 0 {g.mutex.Unlock()return errors.New(request is fail)}g.sreSlide.PushBack(NewSlideval(WithReqOption(1)))err : invoker(ctx, method, req, req, cc, opts...)if err nil {g.sreSlide.PushBack(NewSlideval(WithAcceptReqOption(1)))}g.mutex.Unlock()return err}
}
这个代码是我在SRE 熔断器写的代码现在重新拿出来是因为具有代表性 。NewSlideval 可以支持多个装饰器遍历装饰器就可以得倒我们想要的功能只要我们去实现这个装饰器。这样的代码在golang 是常用的在初始化配置函数经常用