函数类型实现接口,隐式回调接口
这是一种技巧, 用于隐式回调接口, 可以做到直接通过函数类型转换就可以实现函数相当于实现了接口.
典型特点是: 函数类型和接口入参出参一致并实现其接口
http包的应用
1.定义路由
http.HandleFunc("/v1/test", handlerTest)
2.HandleFunc的第二个参数就是func(ResponseWriter, *Request)函数类型, 和下面的Handler接口类型是一致的
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
3.通过HandlerFunc函数类型把路由响应函数转换为HandlerFunc类型
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
4.HandlerFunc和Handler接口一致并实现Handler接口. 把函数类型转换接口, 用于隐式回调接口, 因为入参出参一致, 并且实现Handler接口
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
5.实现了Handler接口的都可以接管http请求, 全部的web框架(gin,beego,echo等)都是从这一步开始框架内部处理(丰富路由, 内部封装context等)
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
nsq中应用
1.Handler接口
type Handler interface {
HandleMessage(message *Message) error
}
2.HandlerFunc函数类型和Handler接口一致并实现接口
type HandlerFunc func(message *Message) error
func (h HandlerFunc) HandleMessage(m *Message) error {
return h(m)
}
nsq中隐式调用接口应用流程
1.使用HandlerFunc函数类型避免定义struct,实现Handler接口,支持隐式调用接口,因为HandlerFunc实现Handler,内部转换为接口了
nsqCconsumer.AddHandler(nsq.HandlerFunc(func(message *nsq.Message) error {
....
return err
}))
2.源码调用逻辑
//添加响应函数
func (r *Consumer) AddHandler(handler Handler) {
r.AddConcurrentHandlers(handler, 1)
}
func (r *Consumer) AddConcurrentHandlers(handler Handler, concurrency int) {
...
for i := 0; i < concurrency; i++ {
go r.handlerLoop(handler)
}
}
func (r *Consumer) handlerLoop(handler Handler) {
...
for {
message, ok := <-r.incomingMessages
...
//nsq收到消息时会回调传入的用户定义处理消息函数
err := handler.HandleMessage(message)
}
...
}
如果没有函数类型转换接口, 那么就需要以下的实现
type Consumers struct {
Topic string
Channel string
Address []string
}
func (c *Consumers) HandleMessage(msg *nsq.Message) error {
return nil
}
consumer.AddHandler(&Consumers{})
有时候只是为了简洁直接使用匿名函数的方式, 那么这样就无法做到了.
因此有了函数类型(实现了对应接口), 实现了内部类型转换, 在内部调用真正的处理函数, 很多开源框架都是有这种骚操作的.
总结
函数类型实现接口,隐式回调接口是一种符合go的设计模式,在很多开源框架否有其存在,因为这样可以实现两种方案的传参。1.通过声明结构体,实现接口,传入结构体指针。2.通过匿名函数类型传入,函数类型实现接口内部回调传入的匿名函数。
这样处理可以方便有时直接匿名函数处理就ok了,不必额外声明结构体再实现接口。