Go中的特殊写法
工程模式的一种写法
基类实现了基本方法, 子类有各种自定义方法.
根据类型选择出一种子类, 通过断言判断该子类是否实现接口, 如果实现就返回该子类, 没有实现就返回基类
type dbInfoFunc interface {
// GetTables 获得所有表列表
GetTables(dbCode string) ([]*engine.Table, error)
// GetColumns 获得一张表的字段信息
GetColumns(dbCode, tableCode string) ([]*engine.Column, error)
// GetTable 获得一张表
GetTable(dbCode string, tableCode string) (*engine.Table, error)
// GetStatistics 获得一张表的索引信息
GetStatistics(dbCode, tableCode string) ([]*engine.Statistic, error)
}
func newDbInfoFunc(dbType xdb.DBType) func(e *mysqlEngine) dbInfoFunc {
var eng interface{}
return func(e *mysqlEngine) dbInfoFunc {
switch dbType {
case xdb.StarRocks:
eng = &StarRocksEngine{eng: e}
case xdb.DRDS:
eng = &DRDSEngine{eng: e}
case xdb.ADB:
eng = &ADBEngine{eng: e}
default:
eng = &defaultEngine{eng: e}
}
if _, ok := eng.(dbInfoFunc); ok {
return eng.(dbInfoFunc)
}
eng = &defaultEngine{eng: e}
return eng.(dbInfoFunc)
}
}
带有优先级的select
从logChan里读日志, 如果收到了结束通知
由于select随机从case中选一个chan的原因, 可能会漏掉一些日志
所以在收到结束通知到, 再select 一下 logChan, 保证把 logChan 中的日志全部读取后再结束
for {
select {
case msg := <-logChan:
logFile.Write(msg)
case <-gcChan:
priority:
for {
select {
case msg := <-logChan:
logFile.Write(msg)
default:
break priority
}
}
return
}
}
}()
子类重载父类的方法
子类Sub 组合了base的方法, B方法会调用A方法
默认情况下Sub.B = base.B -> base.A
重载base的方法后
Sub.B = base.B -> Sub.A
- base
type Manager struct {
lock *sync.RWMutex
allExecutors map[types.Name]taskexecutor.TaskExecutor
workspace string
workspaceDir string
// ***
createExecutorFunc func(ctx context.Context, task *spec.PipelineTask) (_ taskexecutor.TaskExecutor, err error)
}
func NewManager(workspace, workspaceDir string, createExecutorFunc func(ctx context.Context, task *spec.PipelineTask) (_ taskexecutor.TaskExecutor, err error)) *Manager {
return &Manager{
lock: &sync.RWMutex{},
allExecutors: make(map[types.Name]taskexecutor.TaskExecutor),
workspace: workspace,
workspaceDir: workspaceDir,
createExecutorFunc: createExecutorFunc,
}
}
func (mgr *Manager) GetExecutor(ctx context.Context, task *spec.PipelineTask) (taskexecutor.TaskExecutor, error) {
created, _, err := mgr.Exist(ctx, task)
if err != nil {
return nil, err
}
name, _err := mgr.MakeExecutorName(ctx, task)
if _err != nil {
return nil, _err
}
if created {
return mgr.allExecutors[name], nil
}
taskExecutor, err := mgr.CreateExecutor(ctx, task)
if err != nil {
return nil, err
}
mgr.lock.Lock()
mgr.allExecutors[name] = taskExecutor
mgr.lock.Unlock()
return taskExecutor, nil
}
func (mgr *Manager) CreateExecutor(ctx context.Context, task *spec.PipelineTask) (_ taskexecutor.TaskExecutor, err error) {
if mgr.createExecutorFunc == nil {
return nil, errors.Errorf("CreateExecutor not support")
}
return mgr.createExecutorFunc(ctx, task)
}
- 子类
type Manager struct {
lock *sync.RWMutex
workspace string
executors map[types.Name]*HttpCall
log *log.Helper
*base.Manager
}
func NewManager(workspace string, log *log.Helper) *Manager {
if workspace == "" {
workspace = types.DefaultWorkSpace
}
manager := &Manager{
lock: &sync.RWMutex{},
workspace: filepath.Join(workspace, workspaceDir),
executors: make(map[types.Name]*HttpCall),
log: log,
}
// ***
manager.Manager = base.NewManager(workspace, workspaceDir, manager.CreateExecutor)
fmt.Printf("%s Plugin %s Use WorkSpace %s \n", xtime.MustFormatTime(time.Now()), Kind, workspace)
return manager
}
func (mgr *Manager) CreateExecutor(ctx context.Context, task *spec.PipelineTask) (taskexecutor.TaskExecutor, error) {
iTaskItr, err := mgr.Validate(ctx, task)
if err != nil {
return nil, err
}
iTask := iTaskItr.(*innerTask)
name, err := mgr.MakeExecutorName(ctx, task)
if err != nil {
return nil, err
}
httpCall := &HttpCall{
id: time.Now().Unix() % 1000,
log: mgr.log,
name: name,
workspace: mgr.workspace,
State: StateInit,
Method: iTask.Method,
URL: iTask.URL,
UrlParams: iTask.UrlParams,
ReqBody: iTask.ReqBody,
TmpLogFilePath: mgr.MakeTaskLogFilePath(task),
Timeout: iTask.Timeout,
Times: iTask.Times,
finishChan: make(chan struct{}),
}
//mgr.lock.Lock()
//mgr.executors[name] = httpCall
//mgr.lock.Unlock()
return httpCall, nil
}