Go factory方法返回接口类型,而不是实现接口的结构

Go factory方法返回接口类型,而不是实现接口的结构,go,interface,factory-method,Go,Interface,Factory Method,我试图创建一个工厂方法,该方法为实现某个接口的结构返回构造函数 下面是一些示例代码,说明了我正在使用的模式 // 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)

我试图创建一个工厂方法,该方法为实现某个接口的结构返回构造函数

下面是一些示例代码,说明了我正在使用的模式

// 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)
}
当我尝试访问接口中未定义的结构上的字段时,会出现错误:

f、 名称未定义类型Foo没有字段或方法名称

我相信问题在于我的构造函数func NewRealFooname string Foo将接口作为返回类型,而不是*RealFoo。但为了将其用作工厂方法的类型Foo构造函数,返回类型必须是Foo接口


如何修复代码以便访问字段f.Name?

您实际上返回的是RealFoo对象,但作为Foo的一个实现

要获取RealFoo结构的字段,请使用类型断言:

f.(RealFoo).Name
或者,如果它不是RealFoo,为了避免恐慌:

或者切换所有或某些可能的Foo类型

如果愿意修改工厂构造函数,还可以从NewRealFoo返回RealFoo,而不是Foo。因为它实现了该接口,所以在任何需要Foo的地方使用它仍然是有效的。这就是在NewRealFoo中,当在返回Foo的函数中返回RealFoo时要做的事情


没有必要在Go中编程Java。@Volker在Go中合适的设计模式是什么?这是一个奇怪的问题。设计模式有助于实现无法用语言自然表达的东西。你为什么认为你需要一个食品工厂?为什么需要在FooConstructor和FooFactory中两次包装一个简单易懂的NewRealFoo?很可能没有必要这样做;不是,将来也不是。例如,即使没有工厂生产施工人员,测试工作也很好。这些都是很好的建议,但我试图避免类型转换,因为这样我需要知道从工厂返回的具体实现,从而违背工厂方法的目的。我想我的问题是我试图访问一个字段,而接口对此一无所知。如果它是所有实现中都存在的一个字段,我应该将它包装在一个方法中,比如f.Name,并将其添加到接口中。你问题的哪一部分我没有回答?
if realFoo, ok := f.(RealFoo); ok {
    _ := realFoo.Name
}
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
}
func NewRealFoo(name string) RealFoo {
    return &RealFoo{Name: name}
}