golang里的 struct 只能有属性, interface只能有方法定义。这点在 java 里很好实现的 abstract class 在这里就不能直接实现, 可以通过struct和interface的结合定义,实现抽象类的类似的功能。
直接上代码:
代码都来之与项目
GitHub – golang fot xxl-job executor
在这个项目里,重构了executor和默认的RestfulExecutor的实现方式, 就是采用了上述的方式。
先定义接口
// executor 执行器
type executor interface {
// Init
// 初始化执行器
Init(opts ...Option)
// Run 启动服务
Run() error
// Registry 注册执行器到 调度中心
Registry()
// UnRegistry 从调度中心在注销执行器
UnRegistry() error
// SetLogHandler 日志handler
SetLogHandler(handler LogHandler)
// Stop 停止服务
Stop()
// Request Callback 执行后回调请求给调度中心
RequestCallback(task *Task, code int64, msg string)
// RegTask
// 注册任务
RegTask(pattern string, task TaskFunc)
}
然后定义我们需要的 抽象类
type Executor struct {
executor
// private
opts Options
address string
regList *taskPool //注册任务列表
runList *taskPool //正在执行任务列表
log log4go.Logger
logHandler LogHandler //日志查询handler
// inner
_impl executor // 这里很关键,是实现抽象类的重要地方
}
// 这里很关键,是实现抽象类的重要地方,封装一个wrap方法,
func (e * Executor ) wrap(_wrap executor) {
e._impl = _wrap
}
实现抽象类里的主要方法
func (e *Executor) Init(opts ...Option) {
for _, o := range opts {
o(&e.opts)
}
e.log = e.opts.logger
e.regList = &taskPool{
data: make(map[string]*Task),
}
e.runList = &taskPool{
data: make(map[string]*Task),
}
e.address = e.opts.ExecutorIp + ":" + e.opts.ExecutorPort
e.log.Info("%v %v", EXECUTOR4G_VERSION, e.address)
go e.Registry() // 这里的Regstry是子类需要实现的方法
}
// Registry 注册执行器到调度中心
func (e *Executor) Registry() { /// 用wrap方式把调用交换具体的子类
e._impl.Registry()
}
子类实现
type RestFulExecutor struct {
Executor
mu sync.RWMutex
}
// Registry
// 注册执行器到调度中心
func (e *RestFulExecutor) Registry() {
t := time.NewTimer(time.Second * 0) //初始立即执行
defer t.Stop()
....
}
最关键的地方,调用
func newExecutor(opts ...Option) executor {
//var exec executor
options := newOptions(opts...)
if options.executorImpl == nil {
// 变相的抽象类的实现
e := &RestFulExecutor{}
e.wrap(e) // 最关键的地方,使用wrap把具体实现子类包装进返回接口
e.opts = options
return e
} else {
return options.executorImpl
}
}
具体代码可以查看项目中的源码
项目地址
推荐几个好工具