Golang整潔接口最佳實(shí)踐

翻譯自:https://qvault.io/2020/03/15/best-practices-for-writing-clean-interfaces-in-go/

woman-3169726_640.jpg

Go中的接口允許我們將不同的類型暫時(shí)視為同一數(shù)據(jù)類型。它們是 Go 程序員工具箱的核心,但新的 Go 開發(fā)者往往會(huì)使用不當(dāng)......導(dǎo)致代碼難以閱讀,易于產(chǎn)生Bug。讓我們來看看Golang接口的一些最佳實(shí)踐。

我經(jīng)常以標(biāo)準(zhǔn)庫(kù)為例,來說明如何寫出干凈的Go接口。標(biāo)準(zhǔn)的錯(cuò)誤接口很簡(jiǎn)單:

type error interface {
    Error() string
}

error接口封裝了任何有Error()方法的類型。該方法不接受任何參數(shù),并返回一個(gè)字符串。例如,讓我們定義一個(gè)表示網(wǎng)絡(luò)問題的結(jié)構(gòu)。

type networkProblem struct {
    message string
    code    int
}

然后,我們定義一個(gè)Error()方法:

func (np networkProblem) Error() string {
    return fmt.Sprintf("network error! message: %s, code: %v", np.message, np.code)
}

Now, we can use an instance of the networkProblem struct wherever an error is accepted.

現(xiàn)在,我們可以在任何接受到錯(cuò)誤的地方使用networkProblem結(jié)構(gòu)的實(shí)例:

func handleErr(err error) {
    fmt.Println(err.Error())
}

np := networkProblem{
    message: "we received a problem",
    code:    404,
}

handleErr(np)

// prints "network error! message: we received a problem, code: 404"

堅(jiān)持小接口

如果你只能從這篇文章中得到一條建議,那就是:讓接口小一點(diǎn)! 接口的目的是為了定義準(zhǔn)確表示一個(gè)想法或概念所必需的最小行為。

下面是標(biāo)準(zhǔn)HTTP包中一個(gè)更大的接口的例子,它是定義最小行為的好例子:

type File interface {
    io.Closer
    io.Reader
    io.Seeker
    Readdir(count int) ([]os.FileInfo, error)
    Stat() (os.FileInfo, error)
}

任何滿足接口行為的類型都可以被HTTP包當(dāng)作一個(gè)文件來處理。這很方便,因?yàn)镠TTP包不需要知道它處理的是磁盤上的文件、網(wǎng)絡(luò)緩沖區(qū),還是簡(jiǎn)單的[]字節(jié)。

接口應(yīng)該沒有滿足類型的知識(shí)

一個(gè)接口不應(yīng)該關(guān)心具體的類型。

下面,假設(shè)我們構(gòu)建一個(gè)用于描述一輛汽車的組件的接口:

type car interface {
    GetColor() string
    GetSpeed() int
    IsFiretruck() bool
}

GetColor()GetSpeed() 方法是汽車領(lǐng)域的知識(shí)。而 IsFiretruck() 則是反模式。此接口應(yīng)該關(guān)注所有汽車的通用方法,而不應(yīng)該關(guān)心它是否是一臺(tái)消防車。 否則,我們還必須在這個(gè)接口中增加:IsPickup(), IsSedan(), IsTank() 等等,沒完沒了了。

相反,當(dāng)給定一個(gè)car的接口實(shí)例時(shí),開發(fā)應(yīng)該根據(jù)類型斷言的原生功能來推斷出子類型?;蛘撸绻咏涌谛枰粋€(gè)子接口,它可以定義為:

type firetruck interface {
    car
    HoseLength() int
}

firetruck接口繼承了汽車的必要方法,并增加了一個(gè)額外的必要方法,使汽車成為消防車。

接口不是類

接口不是類,應(yīng)該是小的。

接口不需要構(gòu)造函數(shù)或析構(gòu)函數(shù),因?yàn)樗鼪]有必要進(jìn)行數(shù)據(jù)的初始化和銷毀。

接口在本質(zhì)上不是分層的,盡管有語(yǔ)法糖來創(chuàng)建接口,而這些接口恰好是其他接口的超集。

接口只負(fù)責(zé)定義函數(shù)簽名,不關(guān)心其具體實(shí)現(xiàn)。在結(jié)構(gòu)方法中,定義一個(gè)接口可以減少重復(fù)代碼。例如,如果5種類型實(shí)現(xiàn)了錯(cuò)誤接口,它們就需要分別實(shí)現(xiàn)Error()函數(shù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容