Factory pattern abstracts the object creation process and logic from the client. We use the Factory pattern to generate object, when we don’t want to instantiate the object directly.
NOTES
In this article, we discuss the implementation of the Factory Pattern in Go.
See the Factory in other languages in the “Other Code Implementations” section. Or, use the link below to check the details of the Factory Pattern-
Implementation
Following these steps to implement Factory pattern in Go-
- Create an interface, that will ensure a common interface for all the item objects. Here we have created “Base” interface.
- Define one struct for each item and implement “Base” interface. We have declared here 2 structs – ExampleStruct1, and ExampleStruct2.
- Define a struct for the factory. Here we have the “Factory” struct.
- For the factory, define a method for generating the object. Here we have “GetExampleObject”. It takes a string as an identifier, generates an object based on that, then returns the object.
- For using the factory create an object of the factory and then use “GetExampleObject” method to generate the desired object.
Here is a simple example of Factory pattern implementation in Golang-
// Factory Pattern
package main
import (
"errors"
"fmt"
"strings"
)
// --- Declare Base interface ---
type Base interface {
Operation1()
Operation2()
}
// --- Interface definition end ---
// --- Define multiple item structs and implement Base interface ---
// Define first item struct
type ExampleStruct1 struct {
}
func NewExampleStruct1() (exampleStruct1 *ExampleStruct1) {
exampleStruct1 = &ExampleStruct1{}
// Set properties if any
return
}
func (exampleStruct1 *ExampleStruct1) Operation1() {
fmt.Println("Executing: ExampleClass1 Operation1")
}
func (exampleStruct1 *ExampleStruct1) Operation2() {
fmt.Println("Executing: ExampleClass1 Operation2")
}
// Define another item struct
type ExampleStruct2 struct {
}
func NewExampleStruct2() (exampleStruct2 *ExampleStruct2) {
exampleStruct2 = &ExampleStruct2{}
// Set properties if any
return
}
func (exampleStruct2 *ExampleStruct2) Operation1() {
fmt.Println("Executing: ExampleClass2 Operation1")
}
func (exampleStruct2 *ExampleStruct2) Operation2() {
fmt.Println("Executing: ExampleClass2 Operation2")
}
// --- Item struct definition end here ---
// --- Define factory ---
type Factory struct {
}
func NewFactory() (factory *Factory) {
factory = &Factory{}
return
}
func (factory *Factory) GetExampleObj(identifier string) (Base, error) {
identifier = strings.ToLower(identifier)
// Generate object based on the identifier passed
switch identifier {
case "example_struct_1": return NewExampleStruct1(), nil
case "example_struct_2": return NewExampleStruct2(), nil
default: return nil, errors.New("unknown identifier")
}
}
// --- Factory definition end ---
// --- Demo ---
func main() {
// Create a factory object
exampleFactory := NewFactory()
// Use the factory object to generate the item object
exampleObj1, err := exampleFactory.GetExampleObj("example_struct_1")
if err == nil {
exampleObj1.Operation1()
exampleObj1.Operation2()
}
// Use factory to generate another item object
exampleObj2, err := exampleFactory.GetExampleObj("example_struct_2")
if err == nil {
exampleObj2.Operation1()
exampleObj2.Operation2()
}
}
// --- Demo end ---
Output of the above code will be as below.
Executing: ExampleClass1 Operation1
Executing: ExampleClass1 Operation2
Executing: ExampleClass2 Operation1
Executing: ExampleClass2 Operation2
Examples
Let’s take a look at a few examples of Factory pattern implementation in Golang.
Example #1: Transport
Let’s take the example of a transport system. Here we have 3 transport items- “Bus”, “Car”, and “Plane”. Factory pattern is used to generate the item objects.
Let’s take a look at the implementation step-by-step.
Transport Interface
- Create a file named “transport.go”.
- Declare “Transport” interface. Here we have declared 3 methods for the interface – “Start”, “Stop”, and “Repair”.
// transport.go
package main
type Transport interface {
Start()
Stop()
Repair()
}
Bike Struct [Item]
- Create a file for the “Bike” struct and name it “bike.go”.
- Create “NewBike” method, which can create new “Bike” object and return it.
- Implement the “Transport” interface for Bike. Define “Start”, “Stop” and “Repair” method as part of the interface implementation.
// bike.go
package main
import "fmt"
type Bike struct {
}
func NewBike() (bike *Bike) {
bike = &Bike{}
return
}
func (bike *Bike) Repair() {
fmt.Println("Bike Repair")
}
func (bike *Bike) Start() {
fmt.Println("Bike started")
}
func (bike *Bike) Stop() {
fmt.Println("Bike Stopped")
}
Car Struct [Item]
- Create a file “car.go”, and define the item struct “Car” in the file.
- Implement “Transport” interface for “Car”.
// car.go
package main
import "fmt"
type Car struct {
}
func NewCar() (car *Car) {
car = &Car{}
return
}
func (car *Car) Repair() {
fmt.Println("Car Repair")
}
func (car *Car) Start() {
fmt.Println("Car started")
}
func (car *Car) Stop() {
fmt.Println("Car Stopped")
}
Plane Struct [Item]
- Create file named “plange.go”.
- Define “Plane” struct and implement “Transport” interface for the struct.
// plane.go
package main
import "fmt"
type Plane struct {
}
func NewPlane() (plane *Plane) {
plane = &Plane{}
return
}
func (plane *Plane) Repair() {
fmt.Println("Plane Repair")
}
func (plane *Plane) Start() {
fmt.Println("Plane started")
}
func (plane *Plane) Stop() {
fmt.Println("Plane Stopped")
}
Transport Factory
- Create file named “transport_factory.go”.
- Define “TransportFactory” struct and create a method named “NewTransportFactory” for generating a new object of “TransportFactory”.
- Create a method named “GetTransport” for the struct. This method will take an identifier (string in this case), then will generate and return an object based on the identifier.
// transport_factory.go
package main
import (
"errors"
"strings"
)
type TransportFactory struct {
}
func NewTransportFactory() (transportFactory *TransportFactory) {
transportFactory = &TransportFactory{}
return
}
func (transportFactory *TransportFactory) GetTransport(identifier string) (Transport, error) {
if strings.ToLower(identifier) == "bike" {
return NewBike(), nil
}
if strings.ToLower(identifier) == "car" {
return NewCar(), nil
}
if strings.ToLower(identifier) == "plane" {
return NewPlane(), nil
}
return nil, errors.New("Unknown Transport Identifier")
}
Demo
- Create a file “main.go”. Declare the “main” function in the file.
- Create an object of “TransportFactory” using the “NewTransportFactory” method.
- Then call the “GetTransport” method of “TransportFactory” to generate object, and also pass the designed identifier (bike, car, plane, etc.) to the function. This will generate an object and return it.
- Call methods (Start, Stop, Repair) of the transport object for using the functionality.
// main.go
package main
func main() {
transportFactory := NewTransportFactory()
transport1, err := transportFactory.GetTransport("bike")
if err == nil {
transport1.Start()
}
transport2, err := transportFactory.GetTransport("car")
if err == nil {
transport2.Start()
transport2.Stop()
}
transport3, err := transportFactory.GetTransport("plane")
if err == nil {
transport3.Start()
}
}
Output
We will get the following output if the above demo code is executed.
Bike started
Car started
Car Stopped
Plane started
Example #2: Transport [Factory Method]
This example demonstrates the Factory method implementation for transport.
In this implementation, we have 2 types of transport- road transport and air transport. Multiple item classes belong to those types of transport.
Transport Interface
- Create file named “transport.go”.
- Declare “Transport” interface, include 3 methods “Repair”, “Start”, “Stop” in the declaration.
// transport.go
package main
type Transport interface {
Repair()
Start()
Stop()
}
Bus Struct [Road Transport Item]
- Create file named “bus.go” for the “Bus” item.
- Define “Bus” struct and implement “Transport” interface for that.
- Also define method “NewBus()” for generating a new “Bus” object.
// bus.go
package main
import "fmt"
type Bus struct {
}
func NewBus() (bus *Bus) {
bus = &Bus{}
return
}
func (bus *Bus) Repair() {
fmt.Println("Bus Repair")
}
func (bus *Bus) Start() {
fmt.Println("Bus started")
}
func (bus *Bus) Stop() {
fmt.Println("Bus Stopped")
}
Bike Struct [Road Transport Item]
- Create file named “bike.go” for the “Bike” item.
- Define “Bike” struct and implement “Transport” interface.
- Also, define the method “NewBike” for generating a new “Bike” object.
// bike.go
package main
import "fmt"
type Bike struct {
}
func NewBike() (bike *Bike) {
bike = &Bike{}
return
}
func (bike *Bike) Repair() {
fmt.Println("Bike Repair")
}
func (bike *Bike) Start() {
fmt.Println("Bike started")
}
func (bike *Bike) Stop() {
fmt.Println("Bike Stopped")
}
Car Struct [Road Transport Item]
- Create a file named “car.go”.
- Define “Car” struct.
- Implement “Transport” interface for the “Car”.
- Also, define method “NewCar” for generating a new “Car” object.
// car.go
package main
import "fmt"
type Car struct {
}
func NewCar() (car *Car) {
car = &Car{}
return
}
func (car *Car) Repair() {
fmt.Println("Car Repair")
}
func (car *Car) Start() {
fmt.Println("Car started")
}
func (car *Car) Stop() {
fmt.Println("Car Stopped")
}
Plane Struct [Air Transport Item]
- Create file “plane.go”.
- Define “Plane” struct and implement “Transport” interface for this.
// plane.go
package main
import "fmt"
type Plane struct {
}
func NewPlane() (plane *Plane) {
plane = &Plane{}
return
}
func (plane *Plane) Repair() {
fmt.Println("Plane Repair")
}
func (plane *Plane) Start() {
fmt.Println("Plane started")
}
func (plane *Plane) Stop() {
fmt.Println("Plane Stopped")
}
Helicopter Struct [Air Transport Item]
- Create a file named “helicopter.go”.
- Define “Helicopter” struct.
- Implement “Transport” interface for “Helicopter” struct.
// helicopter.go
package main
import "fmt"
type Helicopter struct {
}
func NewHelicopter() (helicopter *Helicopter) {
helicopter = &Helicopter{}
return
}
func (helicopter *Helicopter) Repair() {
fmt.Println("Helicopter Repair")
}
func (helicopter *Helicopter) Start() {
fmt.Println("Helicopter started")
}
func (helicopter *Helicopter) Stop() {
fmt.Println("Helicopter Stopped")
}
Transport Factory
Let’s define the factory implementation.
We have the main “TransportFactory” and then 2 child factories (“RoadTransportFactory” and “AirTransportFactory”).
“TransportFactory” acts as an abstract class here. As we can not directly implement an abstract class in Go, so the “TransportFactory” and other factory implementation becomes a little bit tricky.
- Create a file named “transport_factory.go”.
- Declare “TransportFactoryInterface” and declare 3 methods there.
- Define “TransportFactory” struct and embed the “TransportFactoryInterface” in that.
- Define method for generating a new object of “TransportFactory” named “NewTransportFactory”.
- Define “OperateTransport” and “RepairTransport” methods as part of the interface “TransportFactoryInterface”.
- Do not define the “GetTransport” method. This method is used to generate new objects of transport and will be defined separately in the child transport factories.
// transport_factory.go
package main
type TransportFactoryInterface interface {
GetTransport(name string) (Transport, error)
OperateTransport(name string)
RepairTransport(name string)
}
type TransportFactory struct {
TransportFactoryInterface
}
func NewTransportFactory() (transportFactory *TransportFactory) {
transportFactory = &TransportFactory{}
return
}
func (transportFactory *TransportFactory) OperateTransport(name string) {
transport, err := transportFactory.GetTransport(name)
if err == nil {
transport.Start()
transport.Stop()
}
}
func (transportFactory *TransportFactory) RepairTransport(name string) {
transport, err := transportFactory.GetTransport(name)
if err == nil {
transport.Repair()
}
}
Road Transport Factory
- Create a file “road_transport_factory.go”.
- Define struct for the factory for the road transports. Here we named it “RoadTransportFactory”.
- Define method “NewRoadTransportFactory” that can generate and return a new “RoadTransportFactory” object.
- Define the “GetTransport” method. Return any of the “Car”, “Bike” or “Bus” object based on the “name”(identifier) param.
// road_transport_factory.go
package main
import (
"errors"
"strings"
)
type RoadTransportFactory struct {
TransportFactory
}
func NewRoadTransportFactory() (roadTransportFactory *RoadTransportFactory) {
roadTransportFactory = &RoadTransportFactory{TransportFactory{}}
roadTransportFactory.TransportFactory.TransportFactoryInterface = roadTransportFactory
return
}
func (roadTransportFactory *RoadTransportFactory) GetTransport(name string) (Transport, error) {
if strings.ToLower(name) == "car" {
return NewCar(), nil
}
if strings.ToLower(name) == "bike" {
return NewBike(), nil
}
if strings.ToLower(name) == "bus" {
return NewBus(), nil
}
return nil, errors.New("unknown identifier for RoadTransportFactory")
}
Air Transport Factory
- Create a file “air_transport_factory.go”.
- Define “AirTransportFactory” struct, and embed the “TransportFactory” into it, which in turn embeds the “TransportFactoryInterface”.
- As a part of the interface implementation define the “GetTransport” method. Return the “Plane” or “Helicopter” object based on the param passed.
// air_transport_factory.go
package main
import (
"errors"
"strings"
)
type AirTransportFactory struct {
TransportFactory
}
func NewAirTransportFactory() (airTransportFactory *AirTransportFactory) {
airTransportFactory = &AirTransportFactory{}
airTransportFactory.TransportFactory.TransportFactoryInterface = airTransportFactory
return
}
func (airTransportFactory *AirTransportFactory) GetTransport(name string) (Transport, error) {
if strings.ToLower(name) == "plane" {
return NewPlane(), nil
}
if strings.ToLower(name) == "helicopter" {
return NewHelicopter(), nil
}
return nil, errors.New("unknown identifier for AirTransportFactory")
}
Demo
- Create a file named “main.go” and define function “main”.
- Create object of “RoadTransportFactory” and “AirTransportFactory”.
- Call the “OperateTransport” and/or “RepairTransport” methods of the factory while passing item identifier(“bus”, “helicopter”, “bike” etc.) to the method.
// main.go
package main
func main() {
roadTransportFactory := NewRoadTransportFactory()
airTransportFactory := NewAirTransportFactory()
roadTransportFactory.OperateTransport("bus")
airTransportFactory.OperateTransport("helicopter")
roadTransportFactory.RepairTransport("bike")
}
Output
The above demo code will generate output as below.
Bus started
Bus Stopped
Helicopter started
Helicopter Stopped
Bike Repair
Source Code
Use the following link to get the source code:
Other Code Implementations
Use the following links to check Factory pattern implementation in other programming languages.