Go語言工廠模式自動註冊——管理多個包的結構體

2020-07-16 10:05:21
本例利用包的 init 特性,將 cls1 和 cls2 兩個包註冊到工廠,使用字串建立這兩個註冊好的結構範例。

完整程式碼的結構如下:

.
└── src
    └── chapter08
        └── clsfactory
            ├── main.go
            └── base
                └── factory.go
            └── cls1
                └── reg.go
            └── cls2
                └── reg.go

本套教學所有原始碼下載地址:https://pan.baidu.com/s/1ORFVTOLEYYqDhRzeq0zIiQ    提取密碼:hfyf
類工廠(具體檔案:…/chapter08/clsfactory/base/factory.go)
package base

// 類介面
type Class interface {
    Do()
}

var (
// 儲存註冊好的工廠資訊
    factoryByName = make(map[string]func() Class)
)

// 註冊一個類生成工廠
func Register(name string, factory func() Class) {
    factoryByName[name] = factory
}

// 根據名稱建立對應的類
func Create(name string) Class {
    if f, ok := factoryByName[name]; ok {
        return f()
    } else {
        panic("name not found")
    }
}
這個包叫base,負責處理註冊和使用工廠的基礎程式碼,該包不會參照任何外部的包。

以下是對程式碼的說明:
  • 第 4 行定義了“產品”:類。
  • 第 10 行使用了一個 map 儲存註冊的工廠資訊。
  • 第 14 行提供給工廠方註冊使用,所謂的“工廠”,就是一個定義為func() Class的普通函數,呼叫此函數,建立一個類範例,實現的工廠內部結構體會實現 Class 介面。
  • 第 19 行定義通過名字建立類範例的函數,該函數會在註冊好後呼叫。
  • 第 20 行在已經註冊的資訊中查詢名字對應的工廠函數,找到後,在第 21 行呼叫並返回介面。
  • 第 23 行是如果建立的名字沒有找到時,報錯。

類1及註冊程式碼(具體檔案:…/chapter08/clsfactory/cls1/reg.go)
package cls1

import (
    "chapter08/clsfactory/base"
    "fmt"
)

// 定義類1
type Class1 struct {
}

// 實現Class介面
func (c *Class1) Do() {
    fmt.Println("Class1")
}

func init() {

    // 在啟動時註冊類1工廠
    base.Register("Class1", func() base.Class {
        return new(Class1)
    })
}
上面的程式碼展示了Class1的工廠及產品定義過程。
  • 第 9~15 行定義 Class1 結構,該結構實現了 base 中的 Class 介面。
  • 第 20 行,Class1 結構的範例化過程叫 Class1 的工廠,使用 base.Register() 函數在 init() 函數被呼叫時與一個字串關聯,這樣,方便以後通過名字重新呼叫該函數並建立範例。

類2及註冊程式碼(具體檔案:…/chapter08/clsfactory/cls2/reg.go)
package cls2

import (
    "chapter08/clsfactory/base"
    "fmt"
)

// 定義類2
type Class2 struct {
}

// 實現Class介面
func (c *Class2) Do() {
    fmt.Println("Class2")
}

func init() {

    // 在啟動時註冊類2工廠
    base.Register("Class2", func() base.Class {
        return new(Class2)
    })
}
Class2 的註冊與 Class1 的定義和註冊過程類似。

類工程主流程(具體檔案:…/chapter08/clsfactory/main.go)
package main

import (
    "chapter08/clsfactory/base"
    _ "chapter08/clsfactory/cls1"  // 匿名參照cls1包, 自動註冊
    _ "chapter08/clsfactory/cls2"  // 匿名參照cls2包, 自動註冊
)

func main() {

    // 根據字串動態建立一個Class1範例
    c1 := base.Create("Class1")
    c1.Do()

    // 根據字串動態建立一個Class2範例
    c2 := base.Create("Class2")
    c2.Do()

}
下面是對程式碼的說明:
  • 第 5 和第 6 行使用匿名參照方法匯入了 cls1 和 cls2 兩個包。在 main() 函數呼叫前,這兩個包的 init() 函數會被自動呼叫,從而自動註冊 Class1 和 Class2。
  • 第 12 和第 16 行,通過 base.Create() 方法查詢字串對應的類註冊資訊,呼叫工廠方法進行範例建立。
  • 第 13 和第 17 行,呼叫類的方法。

執行下面的指令進行編譯:

export GOPATH=/home/davy/golangbook/code
go install chapter08/clsfactory
$GOPATH/bin/clsfactory

程式碼輸出如下:

Class1
Class2