我們怎么做才能既不需要寫很多注釋,又能保證代碼易于理解呢?

其中一個主要的方法就是讓代碼自文檔化。其優(yōu)勢在于,既不用寫注釋,又能使得代碼易于維護(hù)。

下面就是三種使得代碼自文檔化的基本方法:

這可能看上去很簡單,但在實際操作過程中會讓人覺得有點(diǎn)棘手。首先你得明白哪些地方有問題以及哪些地方適用這些方法。

除了上面三個以外,還有一些應(yīng)用范圍也比較廣的方法:

接下來我們將具體講一講如何在實際應(yīng)用中運(yùn)用上面這5個方法。

1.命名

先看幾個如何運(yùn)用命名的方法來闡述代碼使得其自文檔化的例子。

重命名函數(shù)

給函數(shù)命名通常都不會太難,但是這里面也有一些需要遵循的簡單規(guī)則:

避免使用含糊的字眼,例如“handle”或“manage”——handleLinks、manageObjects。

使用主動動詞——cutGrass、sendFile,以表示函數(shù)主動執(zhí)行。

指定返回值類型——getMagicBullet、READFILE。強(qiáng)類型的語言也可以用類型標(biāo)識符來表明函數(shù)的返回值類型。

重命名變量

指定單位——如果里面有數(shù)值參數(shù),那可以加上其單位。例如,用widthPx來取代width以指定寬度的單位是像素。

不要使用快捷鍵——a和b都不能作為參數(shù)名。

封裝函數(shù)

關(guān)于這一點(diǎn),我們將舉幾個如何把代碼封裝成函數(shù)的例子。此外,這么做還有一個好處是,可以避免重復(fù)代碼。

將代碼封裝成函數(shù)

這是最基本的:將代碼封裝成函數(shù)以明確其目的。

猜猜下面這行代碼是干什么的:

var width = (value - 0.5) * 16;

好像不是很清楚,當(dāng)然有注釋就一清二楚了,但是我們完全可以封裝成函數(shù)以實現(xiàn)自文檔化……

var width = emToPixels(value);

function emToPixels(ems) {
    return (ems - 0.5) * 16;
}

唯一改變的是計算過程被轉(zhuǎn)移到了一個函數(shù)里。該函數(shù)名明確地表達(dá)了它要做什么,這樣一來就不必寫注釋了。而且,如果有需要后面還可以直接調(diào)用此函數(shù),一舉兩得,減少了重復(fù)勞動。

用函數(shù)表示條件表達(dá)式

If語句如果包含多個運(yùn)算對象,不寫注釋的話理解起來就比較難。

if(!el.offsetWidth || !el.offsetHeight) {
}

知道上面這代碼的目的不?

function isVisible(el) {
    return el.offsetWidth && el.offsetHeight;
}

if(!isVisible(el)) {
}

其實,只要將這些代碼封裝到一個函數(shù)里,那就很容易理解了。

引入變量

最后再講講如何引入變量。相較于上面兩個方法,這個可能沒那么有用,但是無論如何,知道比不知道好。

用變量替換表達(dá)式

還是上面這個if語句的例子:

if(!el.offsetWidth || !el.offsetHeight) {
}

這次我們不封裝函數(shù),改用引入變量:

var isVisible = el.offsetWidth && el.offsetHeight;
if(!isVisible) {
}

用變量替換程式

我們也可以用來清楚說明復(fù)雜程式:

return a * b + (c / d);
var divisor = c / d;
var multiplier = a * b;
return multiplier + divisor;

類和模塊接口

類和模塊的接口——也是面向公共的方法和屬性——有點(diǎn)像說明如何使用的文檔。

看個例子:

class Box {
    public function setState(state) {
        this.state = state;
    }

    public function getState() {
        return this.state;
    }
}

這個類也可以包含其他代碼。我特意舉這個例子是想說明公共接口如何自文檔化。

你能說出這個類是如何被調(diào)用的嗎?很顯然,這并不明顯。

這兩個函數(shù)都應(yīng)該換個合理的名字以表述它們的目的。但即便做到這一點(diǎn),我們還是不怎么清楚如何使用。然后就需要閱讀更多的代碼或者翻閱文檔。

但是如果我們這樣改一下呢……

class Box {
    public function open() {
        this.state = open;
    }

    public function close() {
        this.state = closed;
    }

    public function isOpen() {
        return this.state == open;
    }
}

明白多了,是吧?請注意,我們只是改動了公共接口,其內(nèi)部表達(dá)與原先的this.state狀態(tài)相同。

這么一改,我們一眼看去就知道怎么用。原先那個函數(shù)名雖然不錯,但是依然讓我們覺得云里霧里,還不如后者直截了當(dāng)。像這樣做一個小小的改動產(chǎn)生大大的影響,何樂而不為呢?

代碼分組

用組來區(qū)分不同的代碼片段也是自文檔化的一種形式。

例如,像這篇文章中說的那樣,我們應(yīng)該盡可能將變量定義在靠近使用它的地方,并且盡可能將變量分門別類。

這也可以用來指定不同代碼組之間的關(guān)系,這樣更加方便其他人知道他們還需要了解哪些代碼組。

看看下面的例子:

var foo = 1;

blah()
xyz();
bar(foo);
baz(1337);
quux(foo);
var foo = 1;
bar(foo);
quux(foo);
blah()
xyz();
baz(1337);

將foo的所有使用組合放在一起,一眼望去就能知道各種關(guān)系。

但是有時候我們不得不在中間調(diào)用一些其他函數(shù)。所以如果可以那就盡量使用代碼分組,如果不可以,那就不要強(qiáng)求。

其他建議

imTricky && doMagic();
if(imTricky) {
    doMagic();
}

很顯然后者更好。

結(jié)論

要想能使代碼自文檔化提高其可維護(hù)性是一個非常漫長的歷程。每個注釋都需要花心力去寫,所以盡量精簡方可省時省力。

然而,自文檔化的代碼永遠(yuǎn)取代不了文檔和注釋。因為代碼在表述上總有其限制,所以寫好注釋亦是不可或缺的。此外,API文檔于類庫而言非常重要,因為光靠閱讀代碼是理解不了的,除非這個類庫真的是小得不能再小。

  哈爾濱品用軟件有限公司致力于為哈爾濱的中小企業(yè)制作大氣、美觀的優(yōu)秀網(wǎng)站,并且能夠搭建符合百度排名規(guī)范的網(wǎng)站基底,使您的網(wǎng)站無需額外費(fèi)用,即可穩(wěn)步提升排名至首頁。歡迎體驗最佳的哈爾濱網(wǎng)站建設(shè)。