Flyweight Design Pattern in Go

1. Definition

The Flyweight Design Pattern is a structural design pattern that aims to reduce the memory usage of large numbers of very similar objects by sharing as much data as possible with related objects. It does this by separating intrinsic state (shared) from extrinsic state (external).

2. Problem Statement

Imagine needing to manage a large number of objects that have some shared properties. Storing these objects individually can lead to massive memory consumption, especially if many of them share the same data.

3. Solution

The Flyweight pattern suggests that you should stop storing shared data within the object. Instead, you can store it externally and pass it to the object when it's needed. The objects will now be very lightweight, thus the name "Flyweight".

4. Real-World Use Cases

1. Text editors that manage character styling. Each character might have some style attributes like bold, italic, etc., but many characters share the same style.

2. Graphics software that uses pattern fills. Each shape uses a pattern, but many shapes use the same pattern.

3. Game platforms that manage a large number of identical objects like trees, buildings, or enemies.

5. Implementation Steps

1. Separate the object's intrinsic state (shared) from its extrinsic state (non-shared).

2. Create a factory that caches objects with various intrinsic states and reuses them when needed.

6. Implementation in Go

// Flyweight Object
type TreeType struct {
	name string
	color string
}
func (t *TreeType) Draw(x, y int) string {
	return fmt.Sprintf("Tree drawn of type %s and color %s at position %d,%d", t.name, t.color, x, y)
}
// Flyweight Factory
type TreeFactory struct {
	treeTypes map[string]*TreeType
}
func (tf *TreeFactory) GetTreeType(name, color string) *TreeType {
	key := name + "_" + color
	if _, exists := tf.treeTypes[key]; !exists {
		tf.treeTypes[key] = &TreeType{name, color}
	}
	return tf.treeTypes[key]
}
// Client code
func main() {
	factory := TreeFactory{treeTypes: make(map[string]*TreeType)}
	pine := factory.GetTreeType("Pine", "Green")
	fmt.Println(pine.Draw(10, 20))
	oak := factory.GetTreeType("Oak", "Brown")
	fmt.Println(oak.Draw(5, 15))
}

Output:

Tree drawn of type Pine and color Green at position 10,20
Tree drawn of type Oak and color Brown at position 5,15

Explanation:

1. TreeType is the Flyweight object with intrinsic state (name and color).

2. TreeFactory is the factory that manages the creation and sharing of TreeType instances.

3. In the client code, rather than instantiating new TreeType directly, the factory (TreeFactory) is asked for an instance. If it exists, it is returned; otherwise, a new one is created, stored, and then returned.

7. When to use?

Use the Flyweight Pattern when:

1. An application uses a large number of objects that share part of their state, but not all.

2. The memory costs of storing these objects are high due to the large quantity.

3. The majority of each object's state data can be made extrinsic.


Comments