假设我们定义一个日志打印器的接口ILogger,还有一个日志打印器工厂接口ILoggerFactory。
package main
type ILogger interface {
Debug(content string)
Debugf(format string, args ...interface{})
Info(content string)
Infof(format string, args ...interface{})
Warn(content string)
Warnf(format string, args ...interface{})
Error(content string)
Errorf(format string, args ...interface{})
}
type ILoggerFactory interface {
GetLogger(ext map[string]interface{}) (ILogger, error)
}
GetLooger(ext map[string]interface{})
type SimpleLoggerFactory struct{}
func (f *SimpleLoggerFactory) Logger(ext map[string]interface{}) (ILogger, error) {
// TODO
return nil, nil
}
作为Golang“一等公民”的函数,其实也能用来实现一个接口,并在一些简单的接口实现场景下,能让代码变得更加的简洁直观。下面先来看看如何用函数来实现接口。
type ILoggerFactory interface {
GetLogger(ext map[string]interface{}) (ILogger, error)
}
type ILoggerFactoryFunc func(ext map[string]interface{}) (ILogger, error)
func (f ILoggerFactoryFunc) GetLogger(ext map[string]interface{}) (ILogger, error) {
return f(ext)
}
ILoggerFactoryFuncILoggerFactoryILoggerFactoryFuncGetLoogerGetLoggerILoggerFactoryFuncGetLoogerILoggerFactoryILoggerFactoryILoggerFactoryFunc
type LoggerType string
const (
Zap LoggerType = "zap"
Logrus LoggerType = "logrus"
)
type ILoggerFactory interface {
GetLogger(ext map[string]interface{}) (ILogger, error)
}
type ILoggerFactoryFunc func(ext map[string]interface{}) (ILogger, error)
func (f ILoggerFactoryFunc) GetLogger(ext map[string]interface{}) (ILogger, error) {
return f(ext)
}
func GetILoggerFactory(loggerType LoggerType) (ILoggerFactory, error) {
switch loggerType {
case Zap:
return ILoggerFactoryFunc(func(ext map[string]interface{})(ILogger, error){
// TODO
return nil, nil
}), nil
case Logrus:
return ILoggerFactoryFunc(func(ext map[string]interface{}) (ILogger, error){
// TODO
return nil, nil
}), nil
default:
return nil, fmt.Errorf("nunsupport logger type")
}
}
总结
- 函数实现接口的局限性
- 针对只有一个方法的接口,才能使用这种写法,典型的场景例如工厂方法模式。
- 这种写法要求接口方法的实现逻辑比较简单,且无状态,对于有状态的接口实现,不建议使用这种写法。例如想实现一个ILoggerFactory的工厂,这个工厂除了要能创建ILogger之外,还需要维护ILogger的回收工作,则不能使用函数来实现工厂接口。
- 函数实现接口需要注意的地方
- 一般都会用匿名函数来实现接口,大多情况下还会使用到Golang的闭包特性,实现时,要注意闭包代码变量的引用与复制问题。