[ROM]《重构》读书笔记:第一组重构|Go主题月

517 阅读2分钟

第一组重构分别是:

Extract Function 提炼函数 / Extract Variable 提炼变量

与之对应的相反的重构:

Inline Function 内联函数 / Inline Variable 内联变量

提炼函数 / 内联函数

例子举的不好,不过大概是这么个意思:

// 提炼函数 举个例子
func Cal(a int8)int8{ // 重构前
    a = a + 1
    a = a * 5
    return a
}

func Cal(a int8)int8{ // 重构后
    return multi5(add1(a))
}


// 内联函数 举个例子
func Cal(a int8)int8{ // 重构前
    a = add1(a)
    a = multi5(a)
    return a
}

func Cal(a int8)int8{ // 重构后
    return add1Andmulti5(a)
}

提炼变量 / 内联变量

// 提炼变量 举个例子
func Cal(a int8)int8{ // 重构前
    return ((a + 1)*5)/2
}
 
func Cal(a int8)int8{ // 重构后
    b := a + 1
    c := b * 5
    return c/2
}

// 封装变量 上述过程相反即可

DEMO

假设我们的服务内需要获取一件商品的价格,商品的价格来源有两张表,一个活动临时表记录活动临时的优惠价格,一个是原价表格记录着商品的原价,数据源不统一的情况下我们希望可以获取到商品当前价格:

func GetProductCurrentPrice(productID uint64)(float,error){
    ...
    tempPrice = rbac.GetTempPrice(productID)
    // ...
    ...
    price  = rbac.GetPrice(productID)
    // ...
    ...
    // 做了一些额外的事,通过对比两个价格返回最终价格
    ...
    return price,nil
}

这个方法内存在诸多的问题:

  1. 调用Rbac服务接口是否应当单独提炼出一个单独的函数?
  2. 如果需要做一些事情来返回最终价格,是否应当考虑提炼函数?

与之对应的重构:

【重构1/2】调用rbac服务中方法应该单独封装为一个函数,用于和rbac服务解耦,这样在rpc接口变更的时候,只需要修改GetPrice方法内的函数即可,而不要全局搜索替换:

func GetPrice(productID uint64)(int){
    return rbac.GetPrice(productID)
}

同理:

func GetTempPrice(productID)(int){
    return rbac.GetTempPrice(productID)
}

【重构2/2】如果真的需要对比两个价格返回新的价格,那么就需要进行提炼函数,因为如果需要一段时间稍微浏览一下才能搞明白这段代码的意图,那么就需要进行提炼函数:

func comparePrice(price,tempPrice int)(int){
    // ...
}

因此针对上述方法,提炼函数重构后应该是:

func GetPrice(){
    // 
}

func GetTempPrice(){
    // 
}

func comparePrice(){
    // 
}

func GetLowerPrice(productID uint64)(int,error){
    ...
    price = GetPrice(productID)
    ...
    
    tempPrice = GetTempPrice(productID)
    ...
    return comparePrice(price,tempPrice),nil
}

或者使用内联函数方式:

func GetLowerPrice(productID uint64)(int,error){
    return comparePrice(GetPrice(productID), GetTempPrice(productID)),nil
}

看起来优雅多了。:P

总结

提炼的关键在于命名。形成函数并给函数命名,改变函数声明可以修改函数的名字,也可以用于添加或者修改参数,是最低级但是最有用的重构。注释往往是一个好的函数名字,试着将注释为函数命名/改名,试着让所有注释变得多余。