重构思维系列2-函数及变量

代码中,一个大的逻辑块,一定会由很多个函数和变量组成起来的,

函数的存在可以降低人们对业务的理解,把一个大的逻辑,由一个一个的函数组成起来,如果函数写的足够好的话,去梳理逻辑时就会很清晰。函数中也会有很多变量的存在,变量的存在让人们更好的理解函数的意义。

下面看一看从重构的角度,对函数和变量的一些重构方法。

1、提炼函数

        提炼函数比较简单,从我对书中作者表达的意思来看,提炼函数就是把啰嗦的代码,按照功能提炼到一个函数里,赋予它意义。

        提炼前:

// 打印信用账单
function printCredit(invoice) {
    
    console.log("********************************")
    console.log("******** Customer Credit *******")
    console.log("********************************")
    
    let totalAmount = 0
    for (const order of invoice.orders) {
        totalAmount += order.amount
    }
    
    // print detail
    console.log('name:' + invoice.name)
    console.log('amount:' + totalAmount)
    console.log('time:' + time.now())

}

        提炼后:

// 打印信用账单
function printCredit(invoice) {
    
    printBanner()
    
    let totalAmount = 0
    for (const order of invoice.orders) {
        totalAmount += order.amount
    }
    printDetail()
    
    // 提炼成一个
    function printBanner() {
        console.log("********************************")
        console.log("******** Customer Credit *******")
        console.log("********************************")
    }
    // 提炼成一个打印账单详情的函数
    function printDetail() {
        console.log('name:' + invoice.name)
        console.log('amount:' + totalAmount)
        console.log('time:' + time.now())
    }
}

        说明:提炼函数,根据我的理解,就是把比较长的内容里,按照功能和定义,对逻辑进行提炼。由于javascript的特性可以把函数写在函数内部,可以为当前函数调用,java没有这样的特性,需要把函数提炼在同级函数,然后调用。

2、内联函数

内联前:

    // 是否需要留资
    private function isNeedPublishflow() {
        return !$this->appidIsDouniu();
    }

    // 是否是豆牛app请求
    private function appidIsDouniu() {
        return in_array(intval($this->app_id), [20, 110, 210]);
    }

内联后:

    private function isNeedPublishflow() {
        return !in_array(intval($this->app_id), [20, 110, 210]);
    }

这个是选自UC中的一处我曾经写的代码,为什么要内联,书中是这么表达的大意是:有的代码已经足够简单并且一目了然了,就没有必要再去强行提炼,这种强行提炼看上去是通过对函数的命名仿佛更加已读,但实际上更有可能是反而增加了阅读的难度,因为本来一行就可以看明白,强行提炼以后还要跳出去去看被提炼出来的函数。

3、提炼变量

提炼前:

// 价格等于 (1)订单数量*价格 - (2)超过500件以上的部分给5%的折扣 + (3)总价格1%的运费(运费最高不超过100元)
function getPrice(order) {
    return order.num * order.price - Math.max(0, order.num - 500) * order.price * 5% + Math.min(order.num * order.price * 1%, 100)
}

如果有这样一串计算价格的代码存在电脑里的时候,没事的时候在那放着并不起眼,当计算如果是有一些小问题的时候,再有人想精心梳理一下这个逻辑的时候,应该会想着原地去世。

提炼后:

function getPrice(order) {
    // 变量提炼,

    // 把基础价格提炼出来
    const basePrice = order.num * order.price

    // 把折扣费用提炼出来
    const discountPrice = Math.max(0, order.num - 500) * order.price * 5%

    // 再把运费提炼出来
    const shippingPrice = Math.min(basePrice * 1%, 100)

    return basePrice - discountPrice + shippingPrice
}

这个案例表达了,当需要很费力才能读懂变量相作用在一起的结果的时候,就需要考虑提炼变量了,提炼的标准就是让人理解起来更简单。

4、内联变量

内联前:

function getPrice(order){
    const totalPrice = order.num * order.price
    return totalPrice
}

内联后:

function getPrice(order){
    return order.num * order.price
}

内联变量和提炼变量是相反的,内联变量和内联函数一样,它们都认为已经挺简单的了,不需要再额外多余的提炼了,这多余的提炼反而让代码变得不简洁、不优雅。

5、封装变量

封装前:

// 假如这是一个全局变量
let defaultOwner = {firstName: "Jack", lastName: "Ma"}


// A处代码
defaultOwner = {firstName: "Jack2", lastName: "Ma2"}

// B处代码
defaultOwner = {firstName: "Jack3", lastName: "Ma3"}

封装后:

function getDefaultOwner {
    return defaultOwner
}

// 所有的修改统一都要走这里开赋值变量
function setDefaultOwer(owner) {
    defaultOwner = owner
}

这里要表达的意思是,可能会有比如一个全局变量,或者一个redis的值,一个项目里到处都是对这个变量的赋值,导致说不清在哪里这个值就被改了,缺少一个控制,把度和读和取放到一个地方。

6、变量改名

改名前:

let a = height * width

改名后:

// 平方米
let squareMetre = height * width

这个是重构的一个方法,把那些命名不好、不规范的命名改名,改成一个有语义的命名,并且用途在上下文中很清晰的状态。

7、引入参数对象

引入前:

function getHistoryChatList(startTime, endTime, customerId, ........) {

    // 业务代码

}

引入后:

function getHistoryChatList(condition) {

    // 业务代码
    // condition.getStartTime()

}


let condition = new Condition(startTime, endTime);

getHistoryChatList(condition)

代码中经常会遇到这种情况,一个函数已经写了十几个参数了,后来随着功能的改变又要往里加参数,越加越多,越加越长,非常不利于代码复用。所以,有必要为这样的长参数的函数,做一下把参数替换成对象,或者map,这样复用更方便、编写更简洁更容易阅读。

8、拆分

拆分,当我看完这一章节之后,我没有理解,这和提炼到底有啥区别,因为在我看来,拆分就是在提炼函数。然后看着看着,再看着看着,我理解了,提炼的意思是把一些逻辑,提炼成一个具有语义的函数,如果在这个被提炼的函数中发现,这个函数存在两个方向,那么就可以继续往更细的拆分成小函数,直到不能拆分为止。如果拆的过细了,就还要再内联回来。所以提炼、拆分、内联是相辅相成的,需要把握他们之间的度,这并没有一个特别标准的标准,代码也是一门艺术,每个人都有每个人自己的理解,把自己的理解在代码中优雅的表达出来,就是代码的艺术。

猜你喜欢

转载自blog.csdn.net/weixin_38256311/article/details/124854456