实现例子

假设我们定义一个日志打印器的接口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的闭包特性,实现时,要注意闭包代码变量的引用与复制问题。