Mastering the Factory Design Pattern in Go
Understanding and Applying the Factory Design Pattern

Search for a command to run...
Understanding and Applying the Factory Design Pattern

No comments yet. Be the first to comment.
Welcome to our "Go Deep" blog series, where we embark on a journey to unravel the mysteries of Golang internals.
A Friendly Guide to Scheduling in Go
An In-Depth Look at Google's Bigtable Data Storage System

My Whimsical Coding Adventures

Hello, fellow coders! Today, we're going to explore the fascinating world of design patterns, specifically focusing on the Prototype design pattern in Golang. If you're passionate about coding and eager to learn, you're in the right place! Prototype ...

Unveil the Power of Singleton for Optimized Golang Applications, While Exploring Its Applications and Trade-offs

A Friendly Guide to the Builder Pattern

Hey there, fellow Go enthusiasts! Today, we're going to explore the exciting world of design patterns, with a focus on the Factory Design Pattern. This pattern can significantly streamline your code, enhance maintainability, and boost reusability. So, if you're looking to take your Go programming skills up a notch, you've come to the right place!

The Factory Design Pattern is a creative design pattern that offers an interface for producing objects in a superclass while enabling subclasses to modify the type of objects created. The pattern favors object composition over inheritance, resulting in a more adaptable and modular approach to object creation.
The Factory Design Pattern comes with an array of benefits, such as:
Encapsulation: By enclosing the object creation process, you can manage which objects are instantiated and how they're initialized, making it easier to handle dependencies and maintain the code.
Code Reusability: The pattern enables better code reusability and organization, leading to more efficient and cleaner code.
Flexibility: Adding or modifying object types becomes much more straightforward, as changes must only be made in the factory rather than throughout the entire codebase.

Before we dive into why the Classic Factory Pattern isn't a perfect fit for Golang, let's briefly discuss the pattern itself. The Classic Factory Pattern typically involves an abstract factory class with a method to create objects. This method is then overridden by concrete factory classes that produce specific objects. One of the key aspects of the Classic Factory Pattern is the use of class-based inheritance.
Now that we have a general understanding of the Classic Factory Pattern, let's explore the reasons it's not suitable for Golang:
Go is not a class-based language like Java or C++. Instead, it's a language that relies on interfaces and struct types to create reusable and extensible code. In Go, there are no classes, and thus, no class-based inheritance. This lack of class-based inheritance makes it difficult to directly apply the Classic Factory Pattern in Golang.
Golang promotes the use of composition over inheritance. This design principle means that in Go, it's more common to build larger, more complex types by composing smaller, simpler types, rather than relying on inheritance hierarchies. This approach is in line with Go's simplicity and its focus on creating clean, maintainable code.
In the Classic Factory Pattern, constructors play a crucial role in the creation of objects. However, Golang does not have built-in support for constructors like other class-based languages do. Instead, Go relies on factory functions or methods to create and initialize objects. While this doesn't prevent us from implementing a factory-like pattern, it does mean we can't directly use the Classic Factory Pattern.
In Golang, polymorphism is achieved using interfaces. This allows for more flexible and modular code, as different types can implement the same interface without being part of the same inheritance hierarchy. This is a different approach from class-based languages, where polymorphism is achieved through class inheritance, which is a core concept in the Classic Factory Pattern.
Let's craft a straightforward example to showcase how the Factory Design Pattern can be put into action in Go. We'll develop a factory to generate objects representing various types of guns.
First and foremost, let's establish the interface for our guns:
package main
type IGun interface {
setName(name string)
setPower(power int)
getName() string
getPower() int
}
Next, we'll create three concrete types that implement the IGun interface - Gun , Ak47 and Musket
// gun.go
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
package main
type Ak47 struct {
Gun
}
func newAk47() IGun {
return &Ak47{
Gun: Gun{
name: "AK47 gun",
power: 4,
},
}
}
// musket.go
package main
type musket struct {
Gun
}
func newMusket() IGun {
return &musket{
Gun: Gun{
name: "Musket gun",
power: 1,
},
}
}
Now, let's put together our factory function, getGun, which accepts a string parameter to decide the type of gun to create:
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")
}
Lastly, let's show how to utilize the getGun() factory function to create and use gun objects:
// 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()
}
When you execute the code above, you'll witness the following output:
Gun: AK47 gun
Power: 4
Gun: Musket gun
Power: 1
The Factory Design Pattern is an invaluable asset for Go programmers. By encapsulating object creation, promoting code reusability, and enhancing flexibility, it helps maintain a clean and efficient codebase. Keep in mind that design patterns aim to improve your code, so always evaluate whether the pattern is suitable for your specific use case. Enjoy coding!
