2017-05-30 13 views
0

Javaの春のようにgolangに依存性を柔軟に注入する方法を知りたいのですが、私が持っているすべてのインタフェースのインスタンスを変更したいのですがいくつかの設定ファイルを変更するだけです。golangでコンフィグレーションファイルの名前でインタフェースのインスタンスを取得する方法

まず私はgetTypeByName()のようないくつかの機能を見つけたいので、私はちょうど、configファイルに「mypkg.structName」のような構造体名を与えると機能によって、その構造体を読み込むことができますが、ありませんがあるようですそのようなゴランの機能。

私が思う最も可能な方法は、すべてのカスタム構造体をロードするstruct register fileを生成するためのローダーモデルを作成することです。

しかし、私はそこにもっと簡単な方法があることを知りたいのですが、この柔軟性を実現するためにいくつかのゴランスタイルの方法がありますか?

+1

facebookの[依存性注入ライブラリ](https://github.com/facebookgo/inject)がありますが、実行時(nilポインタタイプ)の傾向があるため、正直言ってdep注入はあまり熱心ではありません。エラー、私はコンパイル時のエラーが好きです。 – Havelock

+0

実行時に設定された依存関係の注入は、私にとって非常に不公平なようです.Goの基本であるコンパイル時の安全性と意図的な単純さを完全に放棄します。 – Adrian

答えて

1

コンパイル時に型が定義されていないと型をインスタンス化できないので、あなたのアプローチは正しいと思います。それ以外の場合は、pluginを使用する必要があります。

かどうかわかりませんが、カスタム構造体を別のパッケージにまとめたい場合は、database/sqlと同様の方法を使用できます。

  1. Factoryインターフェイスで構成され、既知のファクトリを管理するファクトリパッケージを定義します。このパッケージは、カスタムファクトリを登録するための関数Registerと、指定された型のインスタンスを作成するための関数Newをエクスポートする必要があります。たとえば:

    package factory 
    
    import (
        "strings" 
        "sync" 
    ) 
    
    type Factory interface { 
        New(name string) (interface{}, bool) 
    } 
    
    var (
        mu  sync.RWMutex 
        factories = make(map[string]Factory) 
    ) 
    
    func Register(pkgName string, f Factory) { 
        mu.Lock() 
        defer mu.Unlock() 
    
        if f == nil { 
         panic("Factory is nil") 
        } 
        if _, exist := factories[pkgName]; exist { 
         panic("Factory already registered") 
        } 
    
        factories[pkgName] = f 
    } 
    
    func New(typeName string) (interface{}, bool) { 
        items := strings.Split(typeName, ".") 
        if len(items) >= 2 { 
         mu.RLock() 
         defer mu.RUnlock() 
         if f, exist := factories[items[0]]; exist { 
          return f.New(items[1]) 
         } 
        } 
        return nil, false 
    } 
    
  2. カスタム構造体とFactoryインターフェイスを実装で構成されたパッケージを作成します。あなたが必要とするよう繰り返しステップ(2)例えば

    package pkga 
    
    import "path/to/your/factory" 
    
    type thisFactory struct { 
    } 
    
    type Alpha struct{} 
    type Beta struct{} 
    type Gamma struct{} 
    
    func (f *thisFactory) New(name string) (interface{}, bool) { 
        switch name { 
        case "Alpha": 
         return &Alpha{}, true 
        case "Beta": 
         return &Beta{}, true 
        case "Gamma": 
         return &Gamma{}, true 
        } 
        return nil, false 
    } 
    
    func init() { 
        factory.Register("pkga", &thisFactory{}) 
    } 
    
  3. init()機能で、すなわちinitalization中に工場を登録します。次のように

  4. 最後に、あなたのメインパッケージには、インスタンスを作成することができます

    package main 
    
    import (
        "fmt" 
    
        "path/to/your/factory" 
        _ "path/to/custom/pkga" 
        _ "path/to/custom/pkgb" 
        //add more packages ... 
    ) 
    
    func main() { 
        a, _ := factory.New("pkga.Alpha") 
        b, _ := factory.New("pkgb.Beta") 
        c, _ := factory.New("pkga.Gamma") 
    
        fmt.Printf("%T %T %T\n", a, b, c) 
    } 
    

更新:実施例がhere可能です。

関連する問題