成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

編寫可維護(hù)的代碼

imingyu / 1396人閱讀

摘要:編寫可維護(hù)的代碼前言我們?cè)谛薷乃舜a的時(shí)候,閱讀他人代碼所花的時(shí)間經(jīng)常比實(shí)現(xiàn)功能的時(shí)間還要更多如果程序結(jié)構(gòu)不清晰,代碼混亂。這樣可以去除重復(fù)的代碼,提高靈活性關(guān)鍵點(diǎn)找出不同的地方和重復(fù)的地方。

編寫可維護(hù)的代碼 前言

我們?cè)谛薷乃舜a的時(shí)候,閱讀他人代碼所花的時(shí)間經(jīng)常比實(shí)現(xiàn)功能的時(shí)間還要更多

如果程序結(jié)構(gòu)不清晰,代碼混亂 。牽一發(fā)而動(dòng)全身。那維護(hù)起來(lái)就更難維護(hù)了

可讀性

可理解性:他人可以接手代碼并理解它

直觀性 : 代碼邏輯清晰

可調(diào)試性 :出錯(cuò)時(shí),方便定位問(wèn)題所在

如何提高可讀性

代碼格式化

適當(dāng)添加注釋

函數(shù)與方法

大段代碼

注釋需有意義

如何優(yōu)化代碼

找出代碼的壞味道

使用重構(gòu)手法將其解決掉

代碼的壞味道

在我們的程序中,可以聞到很多的壞味道。主要有以下這些點(diǎn)

命名不規(guī)范或無(wú)意義

命名存在使用縮寫、不規(guī)范、無(wú)意義

例子:var a = xxx,b = xxx

重復(fù)代碼

相同(或相似)的代碼在項(xiàng)目中出現(xiàn)了多次,如果需求發(fā)生更改,則需要同時(shí)修改多個(gè)地方

過(guò)長(zhǎng)函數(shù)

程序越長(zhǎng)越難理解,一個(gè)函數(shù)應(yīng)該只完成一個(gè)功能

過(guò)長(zhǎng)的類

一個(gè)類的職責(zé)過(guò)多,一個(gè)類應(yīng)該是一個(gè)獨(dú)立的整體。

過(guò)長(zhǎng)參數(shù)列表

太長(zhǎng)的參數(shù)列表難以理解,不易使用。當(dāng)需要修改的時(shí)候,會(huì)更加容易出錯(cuò)

數(shù)據(jù)泥團(tuán)

有些數(shù)據(jù)項(xiàng)總是成群結(jié)隊(duì)的待在一起。例如兩個(gè)類中相同的字段、許多函數(shù)簽名相同的參數(shù)。

這些都應(yīng)該提煉到一個(gè)對(duì)象中,將很多參數(shù)列縮短,簡(jiǎn)化函數(shù)調(diào)用

類似的函數(shù)

整體上實(shí)現(xiàn)的功能差不多,但是由于有一點(diǎn)點(diǎn)區(qū)別。所以寫成了多個(gè)函數(shù)

重構(gòu)手法 提煉函數(shù)

針對(duì)一個(gè)比較長(zhǎng)的函數(shù),提煉成一個(gè)個(gè)完成特定功能的函數(shù)。

例子
// 提煉前
function test11() {
    var day = $("day");
    var yearVal = "2016";
    var monthVal = "10";
    var dayVal = "10";
    day.val(dayVal);
    switch (monthVal) {
        case 4:
        case 6:
        case 9:
        case 11:
            if (dayVal > 30) {
                day.val(30);
            }
            break;
        case 2:
            if (
                yearVal % 4 == 0 &&
                (yearVal % 100 != 0 || yearVal % 400 == 0) &&
                monthVal == 2
            ) {
                if (dayVal > 29) {
                    day.val(29);
                }
            } else {
                if (dayVal > 28) {
                    day.val(28);
                }
            }
            break;
        default:
            if (dayVal > 31) {
                day.val(31);
            }
    }
}
// 提煉后
function test12() {
    var day = $("day");
    var yearVal = "2016";
    var monthVal = "10";
    var dayVal = "10";

    var maxDay = getMaxDay(yearVal, monthVal);
    if (dayVal > maxDay) {
        day.val(maxDay);
    } else {
        day.val(dayVal);
    }
}

function getMaxDay(year, month) {
    var maxDay = 0;
    switch (month) {
        case 4:
        case 6:
        case 9:
        case 11:
            maxDay = 30;
            break;
        case 2:
            if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) {
                maxDay = 29;
            } else {
                maxDay = 28;
            }
            break;
        default:
            maxDay = 31;
    }
    return maxDay;
}
例子中,提煉前的代碼,需要很費(fèi)勁的看完整個(gè)函數(shù),才會(huì)明白做了什么處理,提煉后的代碼。只需要稍微看一下,就知道 getMaxDay 是獲取當(dāng)前月份的最大天數(shù)
優(yōu)點(diǎn):

如果每個(gè)函數(shù)的粒度都很小,那么函數(shù)被復(fù)用的機(jī)會(huì)就更大;

這會(huì)使高層函數(shù)讀起來(lái)就想一系列注釋;

如果函數(shù)都是細(xì)粒度,那么函數(shù)的覆寫也會(huì)更容易些

內(nèi)聯(lián)函數(shù)

有時(shí)候,一個(gè)函數(shù)的本體與函數(shù)名一樣簡(jiǎn)單易懂,就要用到這種手法。

這種手法用于處理優(yōu)化過(guò)度的問(wèn)題

舉個(gè)例子:

function biggerThanZero(num) {
    return num > 0;
}
function test() {
    var num = 10;
    if (biggerThanZero(num)) {
        //do something
    }
}
//內(nèi)聯(lián)后
function test() {
    var num = 10;
    if (num > 0) {
        //do something
    }
}
引入解釋性變量

當(dāng)表達(dá)式比較復(fù)雜難以閱讀的時(shí)候,就可以通過(guò)臨時(shí)變量來(lái)幫助你將表達(dá)式分解為容易管理的形式

有些時(shí)候,運(yùn)用提煉函數(shù)會(huì)更好一點(diǎn)

舉兩個(gè)簡(jiǎn)單的例子:

// 例子 1
// before
function test2() {
    if (
        platform.toUpperCase().indexOf("MAC") > -1 &&
        browser.toUpperCase().indexOf("IE") > -1 &&
        wasInitialized() &&
        resize > 0
    ) {
        // do something
    }
}
// after
function test2() {
    var isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
    var isIEBrowser = browser.toUpperCase().indexOf("IE") > -1;
    var wasResized = resize > 0;
    if (isMacOs && isIEBrowser && wasInitialized() && wasResized) {
        // do something
    }
}
// --------------------------------------------------

// 例子2
// before
function caluPrice(quantity, itemPrice) {
    return (
        quantity * itemPrice -
        Math.max(0, quantity - 500) * itemPrice * 0.05 +
        Math.min(quantity * itemPrice * 0.1, 100)
    );
}

// after
function caluPrice(quantity, itemPrice) {
    var basePrice = quantity * itemPrice;
    var discount = Math.max(0, quantity - 500) * itemPrice * 0.05;
    var shiping = Math.min(basePrice * 0.1, 100);
    return basePrice - discount + shiping;
}
在兩個(gè)例子中,引入解釋性的變量之后,可讀性大大增加。函數(shù)的意圖就比較明顯,單看變量命名就已經(jīng)能大概知道具體的實(shí)現(xiàn)
分解臨時(shí)變量

除了 for 循環(huán)里用來(lái)收集結(jié)果的變量,其他的臨時(shí)變量都應(yīng)該只被賦值一次。

因?yàn)楸毁x值超過(guò)一次,就意味著他在函數(shù)中承擔(dān)了多個(gè)責(zé)任。

一個(gè)變量承擔(dān)多個(gè)責(zé)任。會(huì)令代碼看起來(lái)容易迷惑

舉個(gè)例子:

// 分解臨時(shí)變量
// before
function test3() {
    var temp = 2 * (width + height);
    console.log(temp);
    // do something
    temp = height * width;
    // do something
    console.log(temp);
}
// after
function test4() {
    var perimeter = 2 * (width + height);
    console.log(perimeter);
    // do something
    var area = height * width;
    // do something
    console.log(area);
}
在這個(gè)例子中,temp 分別被賦予了兩次,如果代碼塊較長(zhǎng)的情況,會(huì)增加風(fēng)險(xiǎn),因?yàn)槟悴恢浪谀睦锉桓牡袅?/pre>
替換算法

當(dāng)你重構(gòu)的時(shí)候,發(fā)現(xiàn)實(shí)現(xiàn)同樣的功能有一個(gè)更清晰的方式,就應(yīng)該將原有的算法替換成你的算法。

舉個(gè)例子:

// 替換算法
// before
function getWeekDay() {
    var weekStr = "";
    switch (date.format("d")) {
        case 0:
            weekStr = "日";
            break;
        case 1:
            weekStr = "一";
            break;
        case 2:
            weekStr = "二";
            break;
        case 3:
            weekStr = "三";
            break;
        case 4:
            weekStr = "四";
            break;
        case 5:
            weekStr = "五";
            break;
        case 6:
            weekStr = "六";
            break;
    }
    return weekStr;
}
// after
function getWeekDay() {
    var weekDays = ["日", "一", "二", "三", "四", "五", "六"];
    return weekDays[date.format("d")];
}
以字面常量取代魔法數(shù)(eg:狀態(tài)碼)

在計(jì)算機(jī)科學(xué)中,魔法數(shù)是歷史最悠久的不良現(xiàn)象之一。

魔法數(shù)是指程序中莫名其妙的數(shù)字。擁有特殊意義,卻又不能明確表現(xiàn)出這種意義的數(shù)字

舉個(gè)例子:

// before
function test5(x) {
    if (x == 1) {
        console.log("完成");
    } else if (x == 2) {
        console.log("上傳中");
    } else if (x == 3) {
        console.log("上傳失敗");
    } else {
        console.log("未知的錯(cuò)誤");
    }
}

function test6(x) {
    if (x == 3) {
        // do something
    }
}

// after
var UploadStatus = {
    START: 0,
    UPLOADING: 1,
    SUCCESS: 2,
    ERROR: 3,
    UNKNOWN: 4
};
function test7(x) {
    if (x == UploadStatus.START) {
        console.log("未開始");
    } else if (x == UploadStatus.UPLOADING) {
        console.log("上傳中");
    } else if (x == UploadStatus.SUCCESS) {
        console.log("上傳成功");
    } else if (x == UploadStatus.ERROR) {
        console.log("上傳失敗");
    } else {
        console.log("未知的錯(cuò)誤");
    }
}

function test8(x) {
    if (x == UploadStatus.ERROR) {
        // do something
    }
}
對(duì)于魔法數(shù),應(yīng)該用一個(gè)枚舉對(duì)象或一個(gè)常量來(lái)賦予其可見的意義。這樣,你在用到的時(shí)候,就能夠明確的知道它代表的是什么意思
而且,當(dāng)需求變化的時(shí)候,只需要改變一個(gè)地方即可
分解條件表達(dá)式

復(fù)雜的條件邏輯是導(dǎo)致復(fù)雜度上升的地點(diǎn)之一。因?yàn)楸仨毦帉懘a來(lái)處理不同的分支,很容易就寫出一個(gè)相當(dāng)長(zhǎng)的函數(shù)

將每個(gè)分支條件分解成新函數(shù)可以突出條件邏輯,更清楚表明每個(gè)分支的作用以及原因

舉個(gè)例子:

// 分解條件表達(dá)式
// 商品在冬季和夏季單價(jià)不一樣
// before
var SUMMER_START = "06-01";
var SUMMER_END = "09-01";
function test9() {
    var quantity = 2;
    var winterRate = 0.5;
    var winterServiceCharge = 9;
    var summerRate = 0.6;
    var charge = 0;
    if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
        charge = quantity * winterRate + winterServiceCharge;
    } else {
        charge = quantity * summerRate;
    }
    return charge;
}

// after
function test9() {
    var quantity = 2;
    return notSummer(date) ? winterCharge(quantity) : summerCharge(quantity);
}

function notSummer(date) {
    return date.before(SUMMER_START) || date.after(SUMMER_END);
}

function summerCharge(quantity) {
    var summerRate = 0.6;
    return quantity * summerRate;
}

function winterCharge(quantity) {
    var winterRate = 0.5;
    var winterServiceCharge = 9;
    return quantity * winterRate + winterServiceCharge;
}
合并條件表達(dá)式

當(dāng)發(fā)現(xiàn)一系列的條件檢查,檢查條件不一樣,但是行為卻一致。就可以將它們合并為一個(gè)條件表達(dá)式

舉個(gè)例子:

// 合并條件表達(dá)式
// before
function test10(x) {
    var isFireFox = "xxxx";
    var isIE = "xxxx";
    var isChrome = "xxxx";
    if (isFireFox) {
        return true;
    }
    if (isIE) {
        return true;
    }
    if (isChrome) {
        return true;
    }
    return false;
}
// after
function test10(x) {
    var isFireFox = "xxxx";
    var isIE = "xxxx";
    var isChrome = "xxxx";
    if (isFireFox || isIE || isChrome) {
        return true;
    }
    return false;
}
合并后的代碼會(huì)告訴你,實(shí)際上只有一個(gè)條件檢查,只是有多個(gè)并列條件需要檢查而已
合并重復(fù)的條件片段

條件表達(dá)式上有著相同的一段代碼,就應(yīng)該將它搬離出來(lái)

// 合并重復(fù)片段
// before
function test11(isSpecial) {
    var total,
        price = 1;
    if (isSpecial) {
        total = price * 0.95;
        // 這里處理一些業(yè)務(wù)
    } else {
        total = price * 0.8;
        // 這里處理一些業(yè)務(wù)
    }
}

// after
function test12(isSpecial) {
    var total,
        price = 1;
    if (isSpecial) {
        total = price * 0.95;
    } else {
        total = price * 0.8;
    }
    // 這里處理一些業(yè)務(wù)
}
在不同的條件里面做了同樣的事情,應(yīng)該將其抽離出條件判斷。這樣代碼量少而且邏輯更加清晰
以衛(wèi)語(yǔ)句取代嵌套條件表達(dá)式

如果某個(gè)條件較為罕見,應(yīng)該多帶帶檢查該條件,并在該條件為真時(shí)立即從函數(shù)中返回。這樣的檢查就叫衛(wèi)語(yǔ)句

舉個(gè)例子:

// 以衛(wèi)語(yǔ)句取代嵌套條件表達(dá)式
// before
function getPayMent() {
    var result = 0;
    if (isDead) {
        result = deadAmount();
    } else {
        if (isSepartated) {
            result = separtedAmount();
        } else {
            if (isRetired) {
                result = retiredAmount();
            } else {
                result = normalPayAmount();
            }
        }
    }
    return result;
}

// after
function getPayMent() {
    if (isDead) {
        return deadAmount();
    }
    if (isSepartated) {
        return separtedAmount();
    }
    if (isRetired) {
        return retiredAmount();
    }
    return normalPayAmount();
}
函數(shù)改名(命名)

當(dāng)函數(shù)名稱不能表達(dá)函數(shù)的用途,就應(yīng)該改名

變量和函數(shù)應(yīng)使用合乎邏輯的名字。

eg:獲取產(chǎn)品列表 -> getProductList()

變量名應(yīng)為名詞,因?yàn)樽兞棵枋龅拇蟛糠质且粋€(gè)事物。

eg: 產(chǎn)品 -> product

函數(shù)名應(yīng)為動(dòng)詞開始,因?yàn)楹瘮?shù)描述的是一個(gè)動(dòng)作

eg:獲取產(chǎn)品列表 -> getProductList()

將查詢函數(shù)和修改函數(shù)分開

如果某個(gè)函數(shù)只向你提供一個(gè)值,沒(méi)有任何副作用。這個(gè)函數(shù)就可以任意的調(diào)用。

這樣的函數(shù)稱為純函數(shù)

如果遇到一個(gè)既有返回值,又有副作用的函數(shù)。就應(yīng)該將查詢與修改動(dòng)作分離出來(lái)

舉個(gè)例子:

// before
function test13(people) {
    for (var i = 0, len = people.length; i < len; i++) {
        if (people[i].name == "andy") {
            // do something 例如進(jìn)行DOM 操作之類的
            return "andy";
        }
        if (people[i].name == "ChunYang") {
            // do something 例如進(jìn)行DOM 操作之類的
            return "ChunYang";
        }
    }
}

// after
function test14(people) {
    var p = find(people);
    // do something 例如進(jìn)行DOM 操作之類的
    // doSomeThing(p);
}

function find(people) {
    for (var i = 0, len = people.length; i < len; i++) {
        if (people[i].name == "andy") {
            return "andy";
        }
        if (people[i].name == "ChunYang") {
            return "ChunYang";
        }
    }
}
令函數(shù)攜帶參數(shù)

如果發(fā)現(xiàn)兩個(gè)函數(shù),做著類似的工作。區(qū)別只在于其中幾個(gè)變量的不同。就可以通過(guò)參數(shù)來(lái)處理。

這樣可以去除重復(fù)的代碼,提高靈活性

關(guān)鍵點(diǎn): 找出不同的地方和重復(fù)的地方。

推薦書籍

《重構(gòu) 改善既有代碼的設(shè)計(jì) 》 基于 java 的

《代碼大全》

相關(guān)鏈接

個(gè)人博客
代碼片段

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/100248.html

相關(guān)文章

  • 讀《編寫維護(hù)javascript》第一章

    摘要:沒(méi)有初始化的變量都會(huì)賦值為盡量避免使用因?yàn)闆](méi)有聲明的變量也會(huì)判斷為類型。對(duì)象直接量,不建議使用構(gòu)造函數(shù)創(chuàng)建對(duì)象數(shù)組直接量,不建議使用構(gòu)造函數(shù)創(chuàng)建數(shù)組 編寫可維護(hù)代碼的重要性 程序是給人讀的,只是偶爾給機(jī)器運(yùn)行一下 1、軟件生命周期的80%成本是發(fā)生在為維護(hù)上;2、幾乎所有的軟件維護(hù)者都不是最初的創(chuàng)建者;3、編寫規(guī)范提高了軟件代碼的可讀性,它讓軟件工程師快速充分的理解代碼; 編寫規(guī)范 縮...

    maxmin 評(píng)論0 收藏0
  • 編寫維護(hù)JavaScript》之編程實(shí)踐

    摘要:最近讀完編寫可維護(hù)的,讓我受益匪淺,它指明了編碼過(guò)程中,需要注意的方方面面,在團(tuán)隊(duì)協(xié)作中特別有用,可維護(hù)性是一個(gè)非常大的話題,這本書是一個(gè)不錯(cuò)的起點(diǎn)。擴(kuò)展閱讀編寫可維護(hù)的歡迎來(lái)到石佳劼的博客,如有疑問(wèn),請(qǐng)?jiān)谠脑u(píng)論區(qū)留言,我會(huì)盡量為您解答。 最近讀完《編寫可維護(hù)的JavaScript》,讓我受益匪淺,它指明了編碼過(guò)程中,需要注意的方方面面,在團(tuán)隊(duì)協(xié)作中特別有用,可維護(hù)性是一個(gè)非常大的話...

    張春雷 評(píng)論0 收藏0
  • 編碼之道(一):程序員“圣經(jīng)“

    摘要:與此類似,理所當(dāng)然的,我們程序員也會(huì)有自己的圣經(jīng)。這便是程序員的圣經(jīng)三個(gè)原則我認(rèn)為做為一個(gè)程序員,最神圣的就是三個(gè)原則,它幾乎能完整無(wú)誤的定義做為一個(gè)程序員應(yīng)該如何去編碼。 ...

    Elle 評(píng)論0 收藏0
  • 編寫維護(hù)JavaScript--編程風(fēng)格篇

    摘要:寫在前面新司機(jī)最近讀完編寫可維護(hù)的,學(xué)到不少東西。書分為編程風(fēng)格編程實(shí)踐自動(dòng)化三個(gè)部分。編程風(fēng)格并不是絕對(duì)的,每個(gè)人或團(tuán)隊(duì)都有自己的編程風(fēng)格,但知道哪些地方需要注意的話,還是有助于新司機(jī)完成代碼風(fēng)格的轉(zhuǎn)變。 寫在前面 新司機(jī)最近讀完《編寫可維護(hù)的JavaScript》,學(xué)到不少東西。書分為編程風(fēng)格、編程實(shí)踐、自動(dòng)化三個(gè)部分。其中編程風(fēng)格是你的代碼格式約定,統(tǒng)一的格式不僅僅有利于團(tuán)隊(duì),也...

    AnthonyHan 評(píng)論0 收藏0
  • <<編寫維護(hù)javascript>> 筆記3(語(yǔ)句和表達(dá)式)

    摘要:所有的塊語(yǔ)句都應(yīng)當(dāng)使用花括號(hào)包括花括號(hào)的對(duì)齊方式第一種風(fēng)格第二種風(fēng)格塊語(yǔ)句間隔第一種在語(yǔ)句名圓括號(hào)和左花括號(hào)之間沒(méi)有空格間隔第二種在左圓括號(hào)之前和右圓括號(hào)之后各添加一個(gè)空格第三種在左圓括號(hào)后和右圓括號(hào)前各添加一個(gè)空格我個(gè)人喜歡在右括號(hào)之后添 所有的塊語(yǔ)句都應(yīng)當(dāng)使用花括號(hào), 包括: if for while do...while... try...catch...finally 3....

    OBKoro1 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<