2016-01-22 69 views
-1

我想創建一個工廠方法,返回一個實現某個接口的結構的構造函數。去工廠方法返回類型接口,而不是實現接口的結構

下面是一些示例代碼,說明我正在使用的模式。

// Generic Interface 
type Foo interface { 
    Bar() string 
} 

type FooConstructor func(name string) Foo 

// A struct that implements Foo 
type RealFoo struct { 
    Name string 
} 

func (f *RealFoo) Bar() string { 
    return f.Name 
} 

func NewRealFoo(name string) Foo { 
    return &RealFoo{Name: name} 
} 

// Factory method to return some FooConstructor 
func FooFactory() FooConstructor { 
    // based on some logic, return some Foo constructor 
    return NewRealFoo 
} 

func main() { 
    ff := FooFactory() 
    f := ff("baz") 
    fmt.Println(f.Bar()) 
    fmt.Println(f.Name) 
} 

http://play.golang.org/p/0RzXlIGAs8

當我嘗試和未接口中定義我的結構進入一個領域,我得到一個錯誤:

f.Name undefined (type Foo has no field or method Name)

我相信問題是,我的構造函數func NewRealFoo(name string) Foo具有作爲返回類型的接口,而不是*RealFoo。但爲了將其用作工廠方法的FooConstructor類型,返回類型必須是Foo接口。

如何修復我的代碼以便我可以訪問該字段f.Name

+1

沒有必要在Go中編程Java。 – Volker

+0

@Volker Go會有什麼合適的設計模式? – adam

+1

這是一個奇怪的問題。設計模式有助於實現不能用語言自然表達的東西。你爲什麼認爲你需要一個'FooFactory'?爲什麼你需要兩次(在FooConstructor和FooFactory中)包裝一個普通,簡單,可理解的'NewRealFoo'?很可能有**沒有**需要**;不是,也不是未來。例如。即使沒有生產構造函數的工廠,測試工作也很好。 – Volker

回答

2

您實際上正在返回RealFoo對象,但作爲Foo的實現。

要獲得RealFoo結構領域中,使用類型斷言:

f.(RealFoo).Name 

,或者爲了避免恐慌,如果它不是一個RealFoo

if realFoo, ok := f.(RealFoo); ok { 
    _ := realFoo.Name 
} 

以上全部或部分開關可能的類型的Foo

switch rf := f.(type) { 
case realFoo: 
    _ := rf.Name // rf is a realFoo 
case unrealFoo: 
    _ := rf.ImaginaryName // rf is an unrealFoo 
case surrealFoo: 
    _ := rf.SurrealName // rf is a surrealFoo 
default: 
    // rf is none of the above types 
} 

的如果您願意修改您的工廠構造函數,您還可以從NewRealFoo返回RealFoo,而不是Foo。由於它實現了該接口,因此在任何地方使用Foo仍然有效。在NewRealFoo中這是你正在做的,當在返回Foo的函數中返回RealFoo時。

func NewRealFoo(name string) RealFoo { 
    return &RealFoo{Name: name} 
} 
+0

這些建議是非常好的,但我試圖避免使用類型轉換,因爲那樣我就需要知道從工廠返回哪個具體的實現,從而破壞了工廠方法的目的。我認爲我的問題是我試圖訪問一個領域,界面一無所知。如果它是所有實現中的一個字段,我應該將其封裝在一個方法中,比如'f.Name()'並將其添加到接口中。 – adam

+0

你已經有'foo.Bar()'。你的問題的哪部分我沒有回答? –