1. 程式人生 > 其它 >winform增加api介面_介面Interface—塑造健壯與可擴充套件的Go應用程式

winform增加api介面_介面Interface—塑造健壯與可擴充套件的Go應用程式

技術標籤:winform增加api介面

本文擬以一個接近實際的專案需求例子,來幫助讀者體會介面使用的重要性,理解Go介面Interface是如何提高專案的魯棒性和擴充套件性。

場景與介面定義

場景:假設有一個線上商城,需要在Go後臺提供儲存與查詢產品的服務。那麼我們在專案中應該怎麼設計該服務?

ok,需求很明朗,其實就是要一個負責儲存和檢索產品的儲存庫。

packageproductrepo

typeProductRepositoryinterface{
StoreProduct(namestring,idint)
FindProductByID(idint)
}

為此,我們建立一個productrepo

的包和一個api.go的檔案。該API應該暴露出儲存庫裡所有的產品方法。在productrepo包下,定義了ProductRepository介面,它代表的就是儲存庫。該介面中我們只定義兩個簡單的方法,StoreProduct()方法用於儲存產品資訊,FindProductByID()方法通過產品ID查詢產品資訊。

介面實現示例

既然已經定義了儲存庫介面,那麼現在就需要有實體物件去實現該介面。

packageproductrepo

import"fmt"

typemockProductRepostruct{

}

func(mmockProductRepo)StoreProduct(namestring,idint){
fmt.Println("mockingtheStoreProductfunc")
}

func(mmockProductRepo)FindProductByID(idint){
fmt.Println("mockingtheFindProductByIDfunc")
}

如上,在productrepo包下,新建mock.go檔案,定義了mockProductRepo物件。正如名字一樣,在示例程式碼中我們並不會真的去做什麼(僅僅做個輸出列印),但是會mock出ProductRepository介面所需的方法。

這時,在api.go檔案中增加一個方法New(),它返回的一個實現了ProductRepository

介面的物件。

funcNew()ProductRepository{
returnmockProductRepo{}
}

為什麼要使用介面?

對於我們已經定義的ProductRepository介面,可以有多種物件去實現它。但是,在最開始做開發時,小菜刀對於介面總是會很疑惑:為什麼要搞個介面,我就一個儲存庫啊(例如本地MySQL儲存),何必要這麻煩!

這種想法,對於小型的個人專案來說可能是正確的。但是,事情往往不是這麼簡單。在複雜的實際應用專案中,我們通常會有很多種儲存物件:例如,你可能選擇使用本地MySQL儲存,也可能連線到雲資料庫(例如阿里雲、谷歌雲和騰訊雲等)儲存。而它們均需要實現ProductRepository介面定義的StoreProduct()方法和FindProductByID()方法。

以本地MySQL儲存庫為例,它要管理產品物件,需要實現ProductRepository介面。

packageproductrepo

import"fmt"

typemysqlProductRepostruct{
}

func(mmysqlProductRepo)StoreProduct(namestring,idint){
fmt.Println("mysqlProductRepo:mockingtheStoreProductfunc")
//InarealworldprojectyouwouldqueryaMySQLdatabasehere.
}

func(mmysqlProductRepo)FindProductByID(idint){
fmt.Println("mysqlProductRepo:mockingtheFindProductByIDfunc")
//InarealworldprojectyouwouldqueryaMySQLdatabasehere.
}

如上,在productrepo包下,新建mysql.go檔案,定義了mysqlProductRepo物件並實現介面方法。

相似地,當專案中同時需要把產品資訊儲存到雲端時,以阿里云為例,在productrepo包下,新建aliyun.go檔案,定義了aliCloudProductRepo物件並實現介面方法。

packageproductrepo

import"fmt"

typealiCloudProductRepostruct{

}

func(maliCloudProductRepo)StoreProduct(namestring,idint){
fmt.Println("aliCloudProductRepo:mockingtheStoreProductfunc")
//InarealworldprojectyouwouldqueryanaliClouddatabasehere.
}

func(maliCloudProductRepo)FindProductByID(idint){
fmt.Println("aliCloudProductRepo:mockingtheFindProductByIDfunc")
//InarealworldprojectyouwouldqueryanaliClouddatabasehere.
}

此時,更新前面提到的api.go中定義的New()方法。

funcNew(environmentstring)ProductRepository{
switchenvironment{
case"aliCloud":
returnaliCloudProductRepo{}
case"local-mysql":
returnmysqlProductRepo{}
}

returnmockProductRepo{}
}

通過將環境變數environment傳遞給New()函式,它將基於該環境值返回ProductRepository介面的正確實現物件。

定義程式入口main.go檔案以及main函式。

packagemain

import"workspace/example/example/productrepo"

funcmain(){
env:="aliCloud"
repo:=productrepo.New(env)
repo.StoreProduct("HuaWeimate40",105)
}

這裡,通過使用productrepo.New()方法基於環境值來獲取ProductRepository介面物件。如果你需要切換產品儲存庫,則只需要使用對應的env值呼叫productrepo.New()方法即可。

最終,本文的程式碼結構如下

.
├──go.mod
├──main.go
└──productrepo
├──aliyun.go
├──api.go
├──mock.go
└──mysql.go

執行main.go,結果如下

$gorunmain.go
aliCloudProductRepo:mockingtheStoreProductfunc

如果沒有介面,要實現上述main函式中的呼叫,需要增加多少程式碼?

//1. 需要為每個物件增加初始化方法

  • msql.go中增加NewMysqlProductRepo()方法

funcNewMysqlProductRepo()*mysqlProductRepo{
return&mysqlProductRepo{}
}
  • aliyun.go中增加NewAliCloudProductRepo()方法

funcNewAliCloudProductRepo()*aliCloudProductRepo{
return&aliCloudProductRepo{}
}
  • mock.go中增加NewMockProductRepo()方法

funcNewMockProductRepo()*mockProductRepo{
return&mockProductRepo{}
}

//2.呼叫物件處產生大量重複程式碼

packagemain

import"workspace/example/example/productrepo"

funcmain(){
env:="aliCloud"
switchenv{
case"aliCloud":
repo:=productrepo.NewAliCloudProductRepo()
repo.StoreProduct("HuaWeimate40",105)
//themorefunctiontodo,themorecodeisrepeated.
case"local-mysql":
repo:=productrepo.NewMysqlProductRepo()
repo.StoreProduct("HuaWeimate40",105)
//themorefunctiontodo,themorecodeisrepeated.
default:
repo:=productrepo.NewMockProductRepo()
repo.StoreProduct("HuaWeimate40",105)
//themorefunctiontodo,themorecodeisrepeated.
}
}

在專案演進過程中,我們不知道會迭代多少儲存庫物件,而通過ProductRepository介面,可以輕鬆地實現擴充套件,而不必反覆編寫相同邏輯的程式碼。

總結

開發中,我們常常提到要功能模組化,本文的示例就是一個典型示例:通過介面為載體,一類服務就是一個介面,介面即服務。

最後,你感受到Go介面賦予應用的高擴充套件性了嗎?


推薦閱讀

  • 探索 Go 中介面的效能

學習交流 Go 語言,掃碼回覆「進群」即可

bcfe97a60e634ab79237e7f2af222720.png

站長 polarisxu

自己的原創文章

不限於 Go 技術

職場和創業經驗

Go語言中文網

每天為你

分享 Go 知識

Go愛好者值得關注

489dacb2753f47eb2343b26b01c6a5fc.png