winform增加api介面_介面Interface—塑造健壯與可擴充套件的Go應用程式
技術標籤:winform增加api介面
本文擬以一個接近實際的專案需求例子,來幫助讀者體會介面使用的重要性,理解Go介面Interface是如何提高專案的魯棒性和擴充套件性。
場景與介面定義
場景:假設有一個線上商城,需要在Go後臺提供儲存與查詢產品的服務。那麼我們在專案中應該怎麼設計該服務?
ok,需求很明朗,其實就是要一個負責儲存和檢索產品的儲存庫。
packageproductrepo
typeProductRepositoryinterface{
StoreProduct(namestring,idint)
FindProductByID(idint)
}
為此,我們建立一個productrepo
介面實現示例
既然已經定義了儲存庫介面,那麼現在就需要有實體物件去實現該介面。
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 中介面的效能
站長 polarisxu
自己的原創文章
不限於 Go 技術
職場和創業經驗
Go語言中文網
每天為你
分享 Go 知識
Go愛好者值得關注