Golang Flyweight Pattern

In this post, we will learn how to use and implement the Flyweight Pattern in Golang with an example.

Flyweight is used to manage the state of an object with high variation. The pattern allows us to share common parts of the object state among multiple objects, instead of each object storing it. Variable object data is referred to as an extrinsic state, and the rest of the object state is intrinsic. Extrinsic data is passed to flyweight methods and will never be stored within it. 

The flyweight pattern helps reduce the overall memory usage and the object initializing overhead. The pattern helps create interclass relationships and lower memory to a manageable level.

Flyweight Pattern Class Diagram

The participants of the flyweight pattern are the FlyWeight interface, ConcreteFlyWeight, FlyWeightFactory, and the Client classes:
  • The FlyWeight interface has a method through which flyweights can get and act on the extrinsic state.
  • ConcreteFlyWeight implements the FlyWeight interface to representflyweight objects.
  • FlyweightFactory is used to create and manage flyweight objects. The client invokes FlyweightFactory to get a flyweight object. UnsharedFlyWeight can have a functionality that is not shared.
  • Client classes

Golang Flyweight Pattern Implementation

Let's say DataTransferObject is an interface with the getId() method. DataTransferObjectFactory creates a data transfer object through getDataTransferObject() by the DTO type. The DTO types are customer, employee,manager, and address.

Let's create a file named "flyweight.go" and add the following source code to it:
package main

// importing fmt package
import (
	"fmt"
)

//DataTransferObjectFactory struct
type DataTransferObjectFactory struct {
	pool map[string]DataTransferObject
}

//DataTransferObjectFactory class method getDataTransferObject
func (factory DataTransferObjectFactory) getDataTransferObject(dtoType string) DataTransferObject {

	var dto = factory.pool[dtoType]

	if dto == nil {

		fmt.Println("new DTO of dtoType: " + dtoType)
		switch dtoType {
		case "customer":
			factory.pool[dtoType] = Customer{id: "1"}
		case "employee":
			factory.pool[dtoType] = Employee{id: "2"}
		case "manager":
			factory.pool[dtoType] = Manager{id: "3"}
		case "address":
			factory.pool[dtoType] = Address{id: "4"}
		}

		dto = factory.pool[dtoType]

	}

	return dto
}

// DataTransferObject interface
type DataTransferObject interface {
	getId() string
}

//Customer struct
type Customer struct {
	id   string //sequence generator
	name string
	ssn  string
}

// Customer class method getId
func (customer Customer) getId() string {
	//fmt.Println("getting customer Id")
	return customer.id

}

//Employee struct
type Employee struct {
	id   string
	name string
}

//Employee class method getId
func (employee Employee) getId() string {
	return employee.id
}

//Manager struct
type Manager struct {
	id   string
	name string
	dept string
}

//Manager class method getId
func (manager Manager) getId() string {
	return manager.id
}

//Address struct
type Address struct {
	id          string
	streetLine1 string
	streetLine2 string
	state       string
	city        string
}

//Address class method getId
func (address Address) getId() string {
	return address.id
}

//main method
func main() {
	var factory = DataTransferObjectFactory{make(map[string]DataTransferObject)}
	var customer DataTransferObject = factory.getDataTransferObject("customer")

	fmt.Println("Customer ", customer.getId())
	var employee DataTransferObject = factory.getDataTransferObject("employee")
	fmt.Println("Employee ", employee.getId())
	var manager DataTransferObject = factory.getDataTransferObject("manager")
	fmt.Println("Manager", manager.getId())
	var address DataTransferObject = factory.getDataTransferObject("address")
	fmt.Println("Address", address.getId())
}

Output:

G:\GoLang\examples>go run flyweight.go
new DTO of dtoType: customer
Customer  1
new DTO of dtoType: employee
Employee  2
new DTO of dtoType: manager
Manager 3
new DTO of dtoType: address
Address 4

Comments