Golang 中的特殊写法 (1)

115 阅读2分钟

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
}