写代码时,控制逻辑的代码往往与业务逻辑混在一起,控制部分的代码很难被复用。
实现功能:从一个channel中批量读取数据,积攒够了50条数据,使用transaction将数据保存到数据库,减少对数据库的访问次数。
实现如下:
func (m *FaceEnroll) createTasks(files <-chan string, tasks chan<- *taskModels.Task) {
batchCount := 50
count := 0
var batchTasks []*taskModels.Task
for {
select {
case file, ok := <-files:
if !ok {
m.SaveTasks(&batchTasks, tasks)
return
}
task := createTaskData(file, m.ID)
batchTasks = append(batchTasks, task)
count++
if count == batchCount {
m.SaveTasks(&batchTasks, tasks)
count = 0
}
default:
m.SaveTasks(&batchTasks, tasks)
time.Sleep(time.Millisecond * 10)
}
}
}
问题:SaveTasks、createTaskData等业务代码与控制代码混在一起,另一个地方也有类似的需求,代码需要完全重新写一遍。
改进:分离控制部分的代码,如下:
func batchExecute(input <-chan interface{}, process func([]interface{})) {
batchMaxCount := 50
index := 0
var batchInputs []interface{}
for {
select {
case i, ok := <-input:
if !ok {
process(batchInputs)
return
}
batchInputs = append(batchInputs, i)
index++
if index == batchMaxCount {
process(batchInputs)
index = 0
}
default:
process(batchInputs)
time.Sleep(time.Millisecond * 10)
}
}
}
其中,process里面是业务逻辑,batchExecute只是实现从input channel中取数据,到一定数量时,调用一次process函数。
小结:控制和业务逻辑分离,复杂度降低了,代码质量提升了。
网友评论