日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

依賴注入與控制反轉:優化Go語言REST API客戶端

來源: 責編: 時間:2023-12-09 15:21:28 298觀看
導讀在這篇文章中,我將探討依賴注入(DI)和控制反轉(IoC)是什么,以及它們的重要性。作為示例,我將使用Monibot的REST API客戶端。讓我們開始吧:一個簡單的客戶端實現我們從一個簡單的客戶端實現開始,允許調用者訪問Monibot的REST AP

在這篇文章中,我將探討依賴注入(DI)和控制反轉(IoC)是什么,以及它們的重要性。作為示例,我將使用Monibot的REST API客戶端。讓我們開始吧:ApV28資訊網——每日最新資訊28at.com

一個簡單的客戶端實現

我們從一個簡單的客戶端實現開始,允許調用者訪問Monibot的REST API,具體來說,是為了發送指標值。客戶端的實現可能如下所示:ApV28資訊網——每日最新資訊28at.com

package monibottype Client struct {}func NewClient() *Client {    return &Client{}}func (c *Client) PostMetricValue(value int) {    body := fmt.Sprintf("value=%d", value)    http.Post("https://monibot.io/api/metric", []byte(body))}

這里有一個客戶端,提供了PostMetricValue方法,該方法用于將指標值上傳到Monibot。我們的庫的用戶可能像這樣使用它:ApV28資訊網——每日最新資訊28at.com

import "monibot"func main() {    // 初始化API客戶端    client := monibot.NewClient()    // 發送指標值    client.PostMetricValue(42)}

依賴注入

現在假設我們想對客戶端進行單元測試。當所有HTTP發送代碼都是硬編碼的時候,我們如何測試客戶端呢?對于每次測試運行,我們都需要一個“真實”的HTTP服務器來回答我們發送給它的所有請求。不可取!我們可以做得更好:讓我們將HTTP處理作為“依賴”;讓我們發明一個 Transport 接口:ApV28資訊網——每日最新資訊28at.com

package monibot// Transport傳輸請求。type Transport interface {    Post(url string, body []byte)}

讓我們再發明一個具體的使用HTTP作為通信協議的Transport:ApV28資訊網——每日最新資訊28at.com

package monibot// HTTPTransport是一個使用HTTP協議傳輸請求的Transport。type HTTPTransport struct {}func (t HTTPTransport) Post(url string, data []byte) {    http.Post(url, data)}

然后讓我們重寫客戶端,使其“依賴”于一個Transport 接口:ApV28資訊網——每日最新資訊28at.com

package monibottype Client struct {    transport Transport}func NewClient(transport Transport) *Client {    return &Client{transport}}func (c *Client) PostMetricValue(value int) {    body := fmt.Sprintf("value=%d", value)    c.transport.Post("https://monibot.io/api/metric", []byte(body))}

現在,客戶端將請求轉發到它的Transport依賴。當創建客戶端時,transport(客戶端的依賴項)被“注入”到客戶端中。調用者可以這樣初始化一個客戶端:ApV28資訊網——每日最新資訊28at.com

import "monibot"func main() {    // 初始化API客戶端    var transport monibot.HTTPTransport    client := monibot.NewClient(transport)    // 發送指標值    client.PostMetricValue(42)}

單元測試

現在我們可以編寫一個使用“偽造”Transport的單元測試:ApV28資訊網——每日最新資訊28at.com

// TestPostMetricValue確保客戶端向REST API發送正確的POST請求。func TestPostMetricValue(t *testing.T) {    transport := &fakeTransport{}    client := NewClient(transport)    client.PostMetricValue(42)    if len(transport.calls) != 1 {        t.Fatal("期望1次傳輸調用,但是是%d次", len(transport.calls))    }    if transport.calls[0] != "POST https://monibot.io/api/metric, body=//"value=42//"" {        t.Fatal("錯誤的傳輸調用 %q", transport.calls[0])    }}// 偽造的Transport是單元測試中使用的Transport。type fakeTransport struct {    calls []string}func (f *fakeTransport) Post(url string, body []byte) {    f.calls = append(f.calls, fmt.Sprintf("POST %v, body=%q", url, string(body)))}

添加更多的Transport函數

現在假設我們庫的其他部分,也使用了Transport功能,需要比POST更多的HTTP方法。對于它們,我們必須擴展我們的Transport接口:ApV28資訊網——每日最新資訊28at.com

package monibot// Transport傳輸請求。type Transport interface {    Get(url string) []byte     // 添加,因為health-monitor需要    Post(url string, body []byte)    Delete(url string)         // 添加,因為resource-monitor需要}

現在我們有一個問題。編譯器抱怨我們的fakeTransport不再滿足Transport接口。所以讓我們通過添加缺失的函數來解決它:ApV28資訊網——每日最新資訊28at.com

// 偽造的Transport是單元測試中使用的Transport。type fakeTransport struct {    calls []string}func (f *fakeTransport) Get(url string) []byte {    panic("不使用")}func (f *fakeTransport) Post(url string, body []byte) {    f.calls = append(f.calls, fmt.Sprintf("POST %v, body=%q", url, string(body)))}func (f *fakeTransport) Delete(url string) {    panic("不使用")}

我們做了什么?由于在單元測試中我們不需要新的Get()和Delete()函數,如果它們被調用,我們就拋出異常。這里有一個問題:每次在Transport中添加新函數時,我們都會破壞現有的fakeTransport實現。對于大型代碼庫來說,這將導致維護噩夢。我們能做得更好嗎?ApV28資訊網——每日最新資訊28at.com

控制反轉

問題在于我們的客戶端(和相應的單元測試)依賴于一個它們不能控制的類型。在這種情況下,它是Transport接口。為了解決這個問題,讓我們通過引入一個未導出的接口,該接口僅聲明了我們的客戶端所需的內容,來反轉控制:ApV28資訊網——每日最新資訊28at.com

package monibot// clientTransport傳輸Client的請求。type clientTransport interface {    Post(url string, body []byte)}type Client struct {    transport clientTransport}func NewClient(transport clientTransport) *Client {    return &Client{transport}}func (c *Client) PostMetricValue(value int) {    body := fmt.Sprintf("value=%d", value)    c.transport.Post("https://monibot.io/api/metric", []byte(body))}

現在讓我們將我們的單元測試更改為使用假的clientTransport:ApV28資訊網——每日最新資訊28at.com

// TestPostMetricValue確保客戶端向REST API發送正確的POST請求。func TestPostMetricValue(t *testing.T) {    transport := &fakeTransport{}    client := NewClient(transport)    client.PostMetricValue(42)    if len(f.calls) != 1 {        t.Fatal("期望1次傳輸調用,但是是%d次", len(f.calls))    }    if f.calls[0] != "POST https://monibot.io/api/metric, body=//"value=42//"" {        t.Fatal("錯誤的傳輸調用 %q", f.calls[0])    }}// 偽造的Transport是在單元測試中使用的clientTransport。type fakeTransport struct {    calls []string}func (f *fakeTransport) Post(url string, body []byte) {    f.calls = append(f.calls, fmt.Sprintf("POST %v, body=%q", url, string(body)))}

由于Go的隱式接口實現(如果愿意,可以稱之為'鴨子類型'),我們庫的用戶什么也不需要改變:ApV28資訊網——每日最新資訊28at.com

import "monibot"func main() {    // 初始化API客戶端    var transport monibot.HTTPTransport    client := monibot.NewClient(transport)    // 發送指標值    client.PostMetricValue(42)}

重新審視Transport

如果我們使IoC成為規范(正如我們應該做的那樣),就不再需要導出Transport接口了。為什么呢?因為如果消費者需要一個接口,讓他們在自己的作用域中定義它,就像我們對'clientTransport'做的那樣。ApV28資訊網——每日最新資訊28at.com

不要導出接口。導出具體實現。如果消費者需要接口,讓他們在自己的作用域中定義。ApV28資訊網——每日最新資訊28at.com

總結

在這篇文章中,我展示了如何以及為什么在Go中使用DI和IoC。正確使用DI/IoC可以導致更易于測試和維護的代碼,特別是在代碼庫不斷增長時。雖然代碼示例是用Go編寫的,但這里描述的原則同樣適用于其他編程語言。ApV28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-40651-0.html依賴注入與控制反轉:優化Go語言REST API客戶端

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 一致性哈希:數據分片與負載均衡的黃金法則

下一篇: 微軟:VS Code已成為Java巨頭!

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 大丰市| 福清市| 成安县| 双辽市| 如东县| 遂宁市| 罗江县| 罗平县| 新津县| 合山市| 纳雍县| 明溪县| 宁明县| 崇左市| 八宿县| 拉孜县| 阿图什市| 云安县| 汉沽区| 建阳市| 邵阳县| 库车县| 峨边| 田林县| 崇信县| 辽源市| 西宁市| 易门县| 深圳市| 南阳市| 慈利县| 奈曼旗| 富裕县| 星座| 莎车县| 固始县| 上犹县| 定州市| 娄底市| 南皮县| 邻水|