课程名称: Go设计模式入门到实践
课程章节: 第5章 结构型模式之装饰模式
主讲老师: Johnny
学习内容:
装饰器模式
概念
动态注入行为的设计模式
对比子类更加灵活,可以对某个对象而不是类造成侵入
步骤及示例
//定义一个抽象组件
type Component interface{
Operate()
}
//实现一个具体的组件
type Component1 struct{}
func (c1 *Component1)Operate() {
fmt.Println("c1 operate")
}
//定义一个抽象的装饰者
type Decorator interface{
Component
Do() //这是相比于Component组件多出的额外的方法
}
//实现一个具体的装饰者
type Decorator1 struct{
c Component
}
func (d1 *Decorator)Do() {
fmt.Println("(d1对)c1发生的一个具体的装饰行为")
}
func (d1 *Decorator)Operate(){
d1.Do()
d1.c.Operate()
}
// 使用
d1 := &Decorator1{}
c1 := &Component1{}
d1.c = c1
d1.Operate()
模拟实战
实现步骤及示例
// 实现一个http server
// 注册一个路由 handler : hello
// 实现中间件功能: 获取请求方法和URL ; 请求网络地址; 请求响应耗时
func hello(w http.ResponseWriter, r *http.Request){
fmt.Fprintf(w, "hello")
}
// 实现方式1 耦合版本
func hello(w http.ResponseWriter, r *http.Request){
log.Printf("请求方式: %s URL: %s", r.Method, r.URL)
log.Printf("请求网络地址: %s", r.RemoteAddr)
startTime := time.Now()
fmt.Printf(w, "hello")
elapsedTime := time.Since(startTime)
log.Printf("耗时: %s", elapsedTime)
}
// 实现方式2 装饰者模式(可以有选择的对路由进行装饰)
func tracing(next http.Handler) http.Handler{
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
log.Printf("请求方式: %s URL: %s", r.Method, r.URL)
next.ServeHTTP(w, r)
})
}
func logging(next http.Handler) http.Handler{
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
log.Printf("请求方式: %s URL: %s", r.Method, r.URL)
next.ServeHTTP(w, r)
})
}
func costing(next http.Handler) http.Handler{
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
startTime := time.Now()
next.ServeHTTP(w, r)
elapsedTime := time.Since(startTime)
log.Printf("耗时: %s", elapsedTime)
})
}
func main(){
// 版本1 http.Handle("/", http.HandlerFunc(hello))
// 装饰者版本
http.Handle("/", tracing(logging(costing(http.HandlerFunc(hello)))))
http.ListenAndServe(":8080", nil)
}
中间件的注册顺序类似于defer 栈的顺序 LIFO
总结