Analysis
It’s impossible to implement the classic Factory Method pattern in Go due to lack of OOP features such as classes and inheritance. However, we can still implement the basic version of the pattern, the Simple Factory.
In this example, we’re going to build various types of weapons using a factory struct.
First, we create the iGun
interface, which defines all methods a gun should have. There is a gun
struct type that implements the iGun interface. Two concrete guns—ak47
and musket
—both embed gun struct and indirectly implement all iGun
methods.
The gunFactory
struct serves as a factory, which creates guns of the desired type based on an incoming argument. The main.go acts as a client. Instead of directly interacting with ak47
or musket
, it relies on gunFactory
to create instances of various guns, only using string parameters to control the production.
Refer to https://swsmile.info/post/design-pattern-factory-pattern/ for Factory pattern.
Example
Product Interface
package main
// Product interface
type iGun interface {
setName(name string)
setPower(power int)
getName() string
getPower() int
}
Concrete product
package main
type gun struct {
name string
power int
}
func (g *gun) setName(name string) {
g.name = name
}
func (g *gun) getName() string {
return g.name
}
func (g *gun) setPower(power int) {
g.power = power
}
func (g *gun) getPower() int {
return g.power
}
ak47.go: Concrete product
package main
type ak47 struct {
gun
}
func newAk47() iGun {
return &ak47{
gun: gun{
name: "AK47 gun",
power: 4,
},
}
}
musket.go: Concrete product
package main
type musket struct {
gun
}
func newMusket() iGun {
return &musket{
gun: gun{
name: "Musket gun",
power: 1,
},
}
}
gunFactory.go: Factory
package main
import "fmt"
func getGun(gunType string) (iGun, error) {
if gunType == "ak47" {
return newAk47(), nil
}
if gunType == "musket" {
return newMusket(), nil
}
return nil, fmt.Errorf("Wrong gun type passed")
}
main.go: Client code
package main
import "fmt"
func main() {
ak47, _ := getGun("ak47")
musket, _ := getGun("musket")
printDetails(ak47)
printDetails(musket)
}
func printDetails(g iGun) {
fmt.Printf("Gun: %s", g.getName())
fmt.Println()
fmt.Printf("Power: %d", g.getPower())
fmt.Println()
}
// output
Gun: AK47 gun
Power: 4
Gun: Musket gun
Power: 1
Reference
- https://refactoring.guru/design-patterns/factory-method/go/example#example-0
- http://tmrts.com/go-patterns/creational/factory.html