I am learning golang, and am getting stuck on an embarassingly simple concept. Maybe it's my OO habits clouding my comprehension, but I can't seem to get this simple example to work:
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!")
}
}
The error is:
prog.go:20:29: not enough arguments in call to method expression datafield.NewField
have (string, string)
want (datafield, string, string)
What is the proper way to get NewField(string,string)
to create a datafield?
You must not set a method on type "datafield" in your case, but do this instead :
func NewField(name, value string) *datafield {
retval := new(datafield)
retval.name = name
retval.value = value
return retval
}
By adding (d datafield) onto the function signature you are making the datafield a receiver argument (https://tour.golang.org/methods/1) so the NewDatafield is now a method on datafield. This means to call it you need to already have a datafield which didn't make much sense so you could just remove the (d datafield) and it will work or even better just construct the stuct directly (https://gobyexample.com/structs):
field := datafield{"name", "value"}
You only really need constructor functions when there is extra work to be done, not just setting fields.
Go isn't exactly object oriented language and promotes simplicity, that's why the previous answers are focused on fixing your code. Nevertheless, if you really need to implement this design pattern in Go, read further.
The factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method. (wikipedia)
Here is another definition and a really good example in Go by Svetlin Ralchev:
The Factory Method pattern is used to define a runtime interface for creating an object. It’s called a factory because it creates various types of objects without necessarily knowing what kind of object it creates or how to create it. (Desing Patterns in Golang: Factory Method)
I've extended your example a bit to demonstrate the benefits of using Factory Methods, as there is no need to use factories at all if you're dealing with one struct (an object in OO world). 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()
}
The program simply prints this
dataField1 -> name1 : value1
dataField2 -> name2 : value2
However, if you look into main func you don't find any mentions or initializations of concrete types dataField1
and dataField2
. All the complexity is hidden behind dataFieldFactories
. Both dataField1Factory
and dataField2Factory
implement Create
interface and return dataField interface, that both the concrete types also implement. So, you can call Print()
for each of the concrete types.
Document.Print()
uses both the Create and Print interfaces for printing out all the fields without any knowledge about how the fields are actually created or printed. We're achieving this by providing a list of Factory Methods (dataField1Factory{}
and dataField2Factory{}
) and corresponding string values to the Document struct (object).
Excuse me for a bit artificial example, but I hope, you'll get the basic idea. As you can see Go allows you to implement design patterns you're familiar with, perhaps, not in exact same way as you get used to in pure OO languages.