A Class Factory in Golang (Google Go)
Do you know what a class factory is and why is it useful? Ever considered implementing a class factory in Golang (Google Go) even though Go is not considered fully object oriented in nature? Are you curious about some awesome features in Go other than it’s impressive concurrency capabilities? If any of the these questions interests you, then reading on may be worth your while. This article covers implementing the factory design pattern in Go.
If that’s not your first time visiting my site, then you probably know by now that the Go programming language is a personal favorite of mine and here’s why. I love software design and I love Go. Because I love software design, I had to learn about design patterns. And one of the most popular design patterns is the concept of factory design patterns. In the OOP world, that translates to class factories. To make diving through the tutorial easier, here are the links to the main sections:
There are tons of definitions for factories currently in the inter-webs, however in it’s core, the concept is fairly simple. A factory or a class factory if you are in the object oriented world, is a design approach that minimizes the pain of adding future code. But why would we need to add future code to an existing application? because that’s the nature of the software industry, you build something that works for your customer, your customer is happy, then they come back asking for more.
The ultimate purpose of a class factory is to help design software in a way where you have a core piece of code that doesn’t need changing, but still able to handle future code without missing a beat. But how does it accomplish that? read on…
A class factory accomplishes decoupling between old and new code in the object oriented world by using interfaces and inheritance. The code will be divided into three pieces:
- Core or main code
- A class factory
- Concrete classes that implement the same interface or abstract class, they also use the same public function signatures
The core code communicates mostly with the class factory, it asks the class factory for a type. The class factory then instantiates the class that represents that type and returns the parent interface of this class to the core code. The core code then calls functions from the interface. The functions are shared by all the classes that implement the interface, which means that whenever the core code is to ask for a different type, the same functions will still work. Here is a full example for a class factory in the object oriented world.
Here is a simple diagram showing the flow of logic for a class factory:
For example, imagine a piece of software responsible for turning a home appliance on. Let’s say that -initially- the appliances you were asked to support were only stoves and fridges. But then a year down the line, you were requested to add support for microwaves as well. If you don’t design it well from the beginning, you will need to change a lot of your existing code. However, if you use a class factory design pattern, the core code of the application needs only to worry about two things: 1- Requesting an appliance of a specific type. 2- Turning on the appliance. The class factory will take care of the rest. The flow of code should look like this:
Core Application code: myAppliance = ApplianceClassFactory.Get(“Oven”)
Class Factory: return new OvenClass
Core Application code: myAppliance.TurnOn()
So How can we write a class factory in Go?
First, after some questions that I received after first publishing the article, I need to be clear that Go is not considered a fully object oriented programming language. That means that when I say a class factory in Go, I don’t literally mean a factory of classes, I just use the term class factory out of habit. In Go, it will be more of a factory of structs, which will be covered very shortly.
Second, before you write a class factory in Go, you need to be familiar with two important building blocks of the language, namely: Structs and Interfaces.
Go structs are the Go equivalent of objects, except that they are much, much simpler. Structs can host both variables and functions. The variables inside the struct get specified in the struct definition statement, whereas functions that belong to a struct identify their parent struct in the function signature.
Let’s complement that with an example, suppose we need a struct with three variables: an integer, a string , and a boolean :
type exampleStruct struct{ num int s string flag bool }
Now let’s assume there is a printExampleStruct() function that belongs to our newly created struct:
//function signature to the right of the func keyword indicates the parent struct type
func (s exampleStruct) printExampleStruct(){
//print the contents of the struct
fmt.Printf("example struct: num = %v, s = %v, flag = %v", s.num, s.s, s.flag)
}
To call and use the struct, we simply need to first initialize a variable of that struct type then use it. The code will look like this:
myStruct := exampleStruct{ num: 5, s: "I am a string variable", flag: true, } myStruct.printExampleStruct()
When we add all of that up and package it, our example struct program will look like this:
package main import "fmt" type exampleStruct struct{ num int s string flag bool } func (s exampleStruct) printExampleStruct(){ fmt.Printf("example struct: num = %v, s = %v, flag = %v", s.num, s.s, s.flag) } func main() { myStruct := exampleStruct{ num: 5, s: "I am a string variable", flag: true, } myStruct.printExampleStruct() }
See how simple was that?? Now, let’s move to the Go interfaces.
Go interfaces are similar in concept to interfaces in mainstream languages like Java or C#. They are in practice a type that defines a set of functions\methods. Since structs act like objects, they typically implement interfaces. The difference in Go is that there are no special keywords and/or braces to indicate that a struct ‘Y’ has inherited interface ‘X’. How it works is that if your struct includes a function that has the same signature as a function inside a defined interface, then your struct implements that interface. Yup, that’s it!!
An interface can be defined simply by the following syntax:
type myInterface interface {
myFunction() float64
}
So as mentioned earlier, any struct that will implement a function of the same signature will be considered to be a child of the interface, here is how the struct will look like:
type myStruct struct{
f float64
}
func (s myStruct)myFunction() float64{
return 455.984
}
A very good example on how interfaces and structs integrate together can be found in Go’s invaluable tour.
Now, with structs and interfaces explained, let’s implement a class factory in Go…
let’s imagine that we were requested to design a program that speaks with multiple types of appliances. The program will either start an appliance or return a description of what the specific appliance does. Say, the current appliance types supported by the program are fridges, and stoves. However, in the future, we may get additional requirements for other appliance types.
In order to design a good piece of software for this purpose, we need to write our program in a way where whenever the customer requests to add more appliances, we won’t need to alter any of our main code. This is when we come into the realization that a class factory would be a good idea for our project.
Let’s start with the core\main application code, Here is what it needs to do for us:
- Ask the user for their preferred appliance type
- Use the class factory to retrieve an appliance of that type
- Turn on the appliance
- Show a description of what the appliance does
So overall, we need four simple tasks implemented in the core application code. That code should not need any edits in the future even if 500 more appliance types get added the next day. It’s now time to take a shot at it in Go:
First, we will need to import the packages used in our core code. A package in Go is similar to a package in Java or a namespace in C#, a large container for code that is a step or two above the class construct. The first package is the one representing the class factory for our project, which is “ClassFactoryTutorial/Appliances” in my case, and the second package is “fmt” which handles a variety of command line tasks. “fmt” is similar to “System” in Java or “Console” in C#.
Second, we write our main function to implement the four tasks described previously. Here is how the code will look like:
package main import ( "ClassFactoryTutorial/Appliances" "fmt" ) func main(){ //Request the user to enter the appliance type fmt.Println("Enter preferred appliance type") //use fmt.scan to retrieve the user's input var myType int fmt.Scan(&myType) //Use the class factory to create an appliance of the requested type myAppliance, err := Appliances.CreateAppliance(myType) //if no errors start the appliance then print it's purpose if err==nil{ myAppliance.Start() fmt.Println(myAppliance.GetPurpose()) } else { //if error encountered, print the error fmt.Println(err) } }
The “Appliances” keyword used in the above code snippet is our class factory, it is nothing more than a package that contains the functions needed to construct our class factory.
Next, let’s create our appliances class factory in Golang,
First, we will need to define an interface that includes the functions needed by any device type.
Second, we will need to write a function that returns a struct type (again, similar to objects in Go) corresponding to the appliance type passed to the class factory from the core code.
package Appliances //import errors to log errors when they occur import "errors" //The main interface used to describe appliances type Appliance interface{ Start() GetPurpose() string } //Our appliance types const ( STOVE = iota FRIDGE ) //Function to create the appliances func CreateAppliance(t int)(Appliance, error) { //Use a switch case to switch between types, if a type exist then error is nil (null) switch t{ case STOVE: return new(Stove),nil case FRIDGE: return new(Fridge),nil default: //if type is invalid, return an error return nil, errors.New("Invalid Appliance Type") } }
The CreateAppliance() function didn’t need to belong to any specific struct or interface, it just belongs to the “Appliances” package. It’s kinda similar to a static method, if you would like to compare with Java or C#.
The appliance types in the code are enum constants, when “iota” is assigned to the first item in the list, the rest of the items will be increments of 0. That means that type “STOVE” will be equal to 0, and type “FRIDGE” will be equal to 1.
And with that, the main body of our class factory is complete. The next step is to write code to represent our supported appliance types, the STOVE struct for stoves and the FRIDGE struct for fridges. In technical terms, we need to write structs (one more time, like classes) that will implement the functions defined in the “Appliance” interface.
Let’s start with the appliance types, we need to write a piece of code that:
- Defines an appliance type struct, “Stove” for stove types or “Fridge” for fridge types
- Implements the “Start()” and the “GetPurpose()” functions. Again these are the functions defined in our class factory “Appliance” interface. By implementing them, the appliance type struct will become an implementation of the “Appliance” interface so any code addressing the “Appliance” interface will work on the appliance type struct
With the functionality fully defined, let’s jump into the code for the “Stove” struct:
package Appliances
// define a stove struct, the struct contain a string representing the type name
type Stove struct{
typeName string
}
//The stove struct implements the start() function
func (sv *Stove)Start(){
sv.typeName = " Stove "
}
//The stove struct implements the GetPurpose() function
func (sv *Stove)GetPurpose() string{
return "I am a " + sv.typeName + " I cook food!!"
}
Pretty straight forward.
Moving on to the “Fridge” struct, the implementation will be very similar:
package Appliances
// define a fridge struct, the struct contain a string representing the type name
type Fridge struct{
typeName string
}
//The fridge struct implements the start() function
func (fr *Fridge)Start(){
fr.typeName = " Fridge "
}
//The fridge struct implements the start() function
func (fr *Fridge)GetPurpose() string{
return "I am a " + fr.typeName + " I cool stuff down!!"
}
And with that, the program is complete. The next step is to use it:
Now, let’s say a week later, the customer comes back and asks for your software to support appliances of type microwave, what would we do? Because we designed our application around a class factory, the additions needed to support something new will be fairly easy and straight forward. Here is what is needed if we are to add support for microwaves:
- Core code (main function) : No change needed
- Class factory code: add type “MICROWAVE”
- Add a new struct that represents the microwave device type
Here are the new additions to the class factory code:
//Our appliance types
const (
STOVE = iota
FRIDGE
//Now we support microwaves
MICROWAVE
)
func CreateAppliance(t int)(Appliance, error) {
switch t{
case STOVE:
return new(Stove),nil
case FRIDGE:
return new(Fridge),nil
//new case added for microwaves
case MICROWAVE:
return new(Microwave),nil
default:
return nil, errors.New("Invalid Appliance Type")
}
And here’s the new Microwave struct:
package Appliances
type Microwave struct{
typeName string
}
func (mr *Microwave)Start(){
mr.typeName = " Microwave "
}
func (mr *Microwave)GetPurpose() string{
return "I am a " + mr.typeName + " I heat stuff up!!"
}
And with that out of the way, we come to the end of the tutorial. As you can see, following a good design from the beginning can save you a lot of grief in the future and makes coding efficient. A powerful and fun language like Go makes it even easier.
The factory in your example is just extra.. bloat code. There is absolutely no need for it. You can simply instantiate any of your objects and pass them to a method expecting that interface. Can you provide a more practical example? Currently.. I just don’t see the need in Go. This also isn’t really a factory “class”.. its just a function. The idiomatic way to do this is have a NewMicrowave or NewStove function in your package for this. Your example requires a never-ending switch as requirements are added.. I would be interested to hear your thoughts on that.
Thanks for your feedback, here are my thoughts\opinions:
1- Regarding the need for the factory part. A good practical example from my experience on when that would be needed is when the project is huge with numerous modules/packages. Typically for mature software organizations, a part of their code will be considered the “core” or “the framework”. This “core” typically do critical tasks like take user input, read configuration files , call other parts of the code, and sometimes even act as the entry point. there is usually a dedicated team for this code that takes care of it. Separate from the core team, there will be other teams dedicated for features or extensions. For the organization to be lean; the core and the features teams need to work in parallel without overlap so the code must be fully decoupled. The factory pattern fits nicely in this scenario as it helps make the core team only focus on the core code without worrying about what new structs or objects the feature teams just created, it acts as a connection point between the two teams. So, in our example, the core code doesn’t need to know there is a struct called stove, it just need to read a “type” from the user input, from a database table or from a configuration file, then it passes this “type” to the factory that takes care of the rest. You are correct that just doing NewStove() or NewFridge() will get the job done. However, the code will be more coupled. That should be fine if it’s a project where a small group of people involved -and I can say that this is my default approach for personal small projects- but that tends to get out of control when you start having numerous teams working in parallel and management with tight timelines.
2- Regarding the term factory class. You are correct and I fully agree, it is not a factory “class” because Go has no classes. I try to clarify that by explaining that the createAppliance()function did not need to belong to any struct or interface. However, I still used the term “class factory” because most programmers nowadays are purely OO programmers and can relate. Having said that, you were not the first one to point out this, I will try to minimize the use of the word “class” in the future in Go articles. The important thing that I would like to note is that this is a guide into implementing the “factory pattern” in Go and has nothing to do with literal object oriented programming
This is a very interesting approach to solve a very common problem. What do you think that instead of using a case statement you have specific methods for each type like BuildStove() ? And return an struct that implements that interface. I think that advantage of that approach will be that the compiler will help you to know which public method the factory have and you can rely on your editor code completion capabilities.
I see you don’t use the power of social websites like facebook on your
site. You can get huge traffic from social sites on autopilot using
one useful tool, for more info search in google for:
Alufi’s Social Automation
I’m glad to see I’m not the only one that makes use of the factory pattern in Go. I’m working a project right now that have around 15 “classes”, each that have multiple dependencies (config structs, HTTP client interface, 3rd party mailer, etc…), and I find that abstracting their creation greatly simplifies the calling code.
I don’t care about the naming…
I’m in the situation where I have to deal with some 90 different “object” type requests I have to serve. Since each type has a unique code assigned the switch comes in handy.
Until I’ve seen your example I’ve been looking for “THE Go idiomatic way”, but to be honest, what is more “Go idiomatic” than pragmatically choose the simplest possible solution to solve a complex problem in a large context.
I fully agree
//The fridge struct implements the start() function
func (fr *Fridge)GetPurpose() string{
return “I am a ” + fr.typeName + ” I cool stuff down!!”
}
Above common error 🙂 should be:
//The fridge struct implements the GetPurpose() function
Sorry, it is “comment” not “common”, my poor english:)
thanks for good review
this is very interesting for your advice i am very proud visit your site
factory method of CreateAppliance always creates a new instance of appliance ,so can be replace with singleton implementation to get same instance eg in java we could do @autowire and return that instance always for factory.
I would be interested to hear your thoughts on that.
I was looking for this, a factory of singletons reutrn the same instance if already exists. Any resources you can point to this?
Best Regards
asaas