首頁 > 軟體

Go泛型應用工廠方法及泛型使用

2022-07-15 10:02:00

前言

由於網上關於泛型使用的文章太多了,這裡就不聊怎麼使用泛型了,今天我們結合工廠方法+泛型方法來看一下泛型到底是如何在業務場景中使用的。本文涉及到的點如下:

  • 介面是怎麼實現泛化程式設計的。
  • 泛型是怎麼解決介面的侷限性的。
  • 泛型使用的最佳時機。
  • 關於功能設計的簡單建議。

話不多說,我們開始吧,具體泛型怎麼使用及語法,請自行查閱相關資料。

介面實現泛化程式設計

平時我們編寫結構體和方法的時候,一般是使用具體的型別:要麼是基本型別,要麼是自定義型別。但是如果要編寫可以應用於多種型別的程式碼的時候,那麼這種限制對程式的束縛就會比較大。

那麼我們想編出一些泛化的方法和介面,怎麼辦呢? 這個時候我們想到了介面,如果方法的引數是一個介面,而不是一個結構體,這樣對程式的限制就會放開了許多。因為任何實現該介面的結構體都可以作為該方法的介面引數,這樣就可以保證後面在新增其他同類功能的時候,只需實現這個介面就可以滿足需求了。

比如如下一個需求:

定義兩個手機品牌結構體華為,蘋果 ,並列印出各自品牌的名字。保證程式的擴充套件性,後面我們可能還要加入小米

import "fmt"
//手機統一介面
type Phone interface {
  PrintBrand()
}
​
type HuaweiPhone struct {
}
func (hw *HuaweiPhone) PrintBrand() {
  fmt.Printf("品牌名字:華為")
}
​
type Iphone struct {
}
func (ip *Iphone) PrintBrand() {
  fmt.Printf("品牌名字:蘋果")
}
//統一列印方法
func PrintBrand(phone Phone) {
  phone.PrintBrand()
}
func main() {
  hw := HuaweiPhone{}
  ip := Iphone{}
  PrintBrand(ip)
  PrintBrand(hw)
}

如上面程式碼,我們定義了兩個手機品牌的結構體,我們想列印各個手機的品牌名字,需要呼叫統一列印方法就可以了,如果後面新增其他品牌的話,我們只需要實現Phone這個介面就可以,如下新增小米手機品牌:

type XiaomiPhone struct {
}
func (xm XiaomiPhone) PrintBrand() {
  fmt.Printf("品牌名字:小米")
}

以上程式碼我們可以看到,通過介面也可以定義一些泛化的行為。

工廠+泛型來實現更通用的泛化程式設計

可是有時候,即便我們使用了介面,對程式的約束依然還是很強,因為一旦我們指明瞭具體的介面,就會要求我們必須使用特定的介面。而我們希望編寫更通用的程式碼,要使程式碼能夠應用於某種不具體的型別,而不是具體的一個介面或者結構體。這個要怎麼辦呢?

比如,我們基於以上的需求繼續加需求

由於我們對接的品牌增大到20種,除了上面三種還有 魅族、三星、諾基亞、中興。。。。等等

這個時候我們基於當前的程式碼已經不能滿足,那麼我們想到了工廠設計模式,在工廠中用泛型來泛化所有的型別,我們通過傳入型別名字來列印出具體的品牌名。我們引入工廠模式繼續優化我們的程式碼,

如下:

var cache sync.Map
//工廠方法 可以傳入任意的型別
func PhoneFactory[T any]() (t *T) {
  target := reflect.TypeOf(t)
  v, ok := cache.Load(t)
  if ok {
    return v.(*T)
  }
  v = new(T)
  v, _ = cache.LoadOrStore(target, v)
  return v.(*T)
}
func main() {
  PrintBrand(PhoneFactory[Iphone]())
  PrintBrand(PhoneFactory[HuaweiPhone]())
  PrintBrand(PhoneFactory[XiaomiPhone]())
}

程式碼中我們編寫了個工廠方法,泛型型別為 any, 接收任意的型別,在工廠中我們建立物件返回相應的型別並快取型別物件防止重複建立。這樣我們後面再加其他類別的時候可以通過這個工廠方法來統一的建立,我們還可以通過反射在建立前後根據業務需要做一些操作。

泛型使用的最佳時機

泛型的加入,無疑增加了程式碼的複雜度,那麼我們使用泛型的最佳時機是什麼時候呢?

Go 泛型主要設計者 Ian Lance Taylor 給出了簡要的泛型使用方針,當開發者發現自己多次編寫完全相同的程式碼,而這些副本之間的唯一區別僅在於使用了不同型別,這時候便可以考慮使用型別引數。換句話說,即開發者應避免使用型別引數,直到發現自己要多次編寫完全相同的程式碼。

關於功能設計的簡單建議

比如說上面的業務,其實我們開始設計的時候設計到介面層面就可以了,如果一開始就引入工廠方法,其實這算是過度設計,我們設計一個功能的原則是,抓住上下文,適度設計,因為一旦我們投入了過多的精力到靈活設計上,勢必會影響本應該完成的需求。同時,過多的功能會引入更多潛在的問題,而修復問題也會耗費我們的時間和精力。而且在當前這個敏捷開發的時代,更是如此。

最後

為了提高可閱讀性,以上程式碼都是以最簡單的方式呈現的,實際業務遠比這要複雜的多,這裡只是提供一種方向。

到此這篇關於Go泛型應用工廠方法及泛型使用的文章就介紹到這了,更多相關Go泛型應用內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com