Golang 工厂方法

SCo*_*ote 2 constructor go

我正在学习 golang,并且被困在一个非常简单的概念上。也许是我的面向对象习惯使我的理解变得模糊,但我似乎无法让这个简单的例子起作用:

package main

import (
    "fmt"
)

type datafield struct {
    name  string
    value string
}

func (d datafield) NewField(name, value string) *datafield {
    retval := new(datafield)
    retval.name = name
    retval.value = value
    return retval
}

func main() {
    field := datafield.NewField("name", "value")
    if field == nil {
        fmt.Println("Error: Did not create a datafield")
    } else {
        fmt.Println("Success!")
    }
}
Run Code Online (Sandbox Code Playgroud)

错误是:

prog.go:20:29: not enough arguments in call to method expression datafield.NewField
    have (string, string)
    want (datafield, string, string)
Run Code Online (Sandbox Code Playgroud)

NewField(string,string)创建数据字段的正确方法是什么?

vit*_*itr 9

Go 并不完全是面向对象的语言并促进了简单性,这就是为什么之前的答案专注于修复您的代码。不过,如果您真的需要在 Go 中实现这种设计模式,请进一步阅读。

工厂方法模式是一种创建模式,它使用工厂方法来处理创建对象的问题,而无需指定将要创建的对象的确切类。这是通过调用工厂方法创建对象来完成的。(维基百科

这是 Svetlin Ralchev 在 Go 中的另一个定义和一个非常好的例子:

工厂方法模式用于定义用于创建对象的运行时接口。之所以称为工厂,是因为它创建了各种类型的对象,而不必知道它创建的是哪种对象或如何创建它。(Golang 中的设计模式:工厂方法

我已经扩展了您的示例以演示使用工厂方法的好处,因为如果您正在处理一个结构(OO 世界中的对象),则根本不需要使用工厂。 https://goplay.space/#SOXPmM86GgF

package main

import (
    "fmt"
)

type dataField interface {
    Print()
}
type dataField1 struct {
    name  string
    value string
}

func (df *dataField1) Print() {
    fmt.Println("dataField1 ->", df.name, ":", df.value)
}

type dataField2 struct {
    name  string
    value string
}

func (df *dataField2) Print() {
    fmt.Println("dataField2 ->", df.name, ":", df.value)
}

type dataFieldFactory interface {
    Create(name, value string) dataField
}

type dataField1Factory struct{}

func (factory *dataField1Factory) Create(name, value string) dataField {
    return &dataField1{
        name:  name,
        value: value,
    }
}

type dataField2Factory struct{}

func (factory *dataField2Factory) Create(name, value string) dataField {
    return &dataField2{
        name:  name,
        value: value,
    }
}

type Document struct {
    dataFieldFactories []dataFieldFactory
    allValues          [][]string
}

func (doc *Document) Print() {
    for i, factory := range doc.dataFieldFactories {
        field := factory.Create(doc.allValues[i][0], doc.allValues[i][1])
        field.Print()
    }
}

func main() {
    doc := &Document{
        dataFieldFactories: []dataFieldFactory{
            &dataField1Factory{},
            &dataField2Factory{},
        },
        allValues: [][]string{{"name1", "value1"}, {"name2", "value2"}},
    }
    doc.Print()
}
Run Code Online (Sandbox Code Playgroud)

该程序只是打印这个

dataField1 -> name1 : value1
dataField2 -> name2 : value2
Run Code Online (Sandbox Code Playgroud)

但是,如果您查看 main func,您不会发现任何具体类型dataField1dataField2. 所有的复杂都隐藏在背后dataFieldFactories。双方dataField1FactorydataField2Factory实现Create界面,返回的dataField接口,这两个具体的类型也实现了。因此,您可以调用Print()每种具体类型。

Document.Print()使用“创建”和“打印”界面打印出所有字段,而无需了解这些字段的实际创建或打印方式。我们通过向文档结构(对象)提供工厂方法(dataField1Factory{}dataField2Factory{})列表和相应的字符串值来实现这一点。

请原谅我举一个有点人为的例子,但我希望,你会明白基本的想法。正如您所看到的,Go 允许您实现您熟悉的设计模式,这可能与您在纯 OO 语言中习惯的方式不同。