Flyweight

Flyweight design pattern is a way to compact large structure into smaller structure with granular shareable structures backed by a caching mechanism. This is commonly seen in GUI implementation where larger widget is broken down into smaller widget and a set of GUI libraries. It requires a factory to manage the flyweight objects.

Also, flyweight design pattern is also use in big data, where a set of data can be so large that it employs caching. This design however, requires client to be disciplined not to create the Flyweight object on his/her own but strictly via its factory generator. This is to ensure the factory is able to cache the object creation.

The diagram is as follows:

When to Use (Problem)

  • Data set is large and requires break-down into smaller pieces and caching reusable parts.

Example (Solution)

Here is an example in Go:

package main

import (
        "fmt"
        "time"
)

// Flyweight is the object that is sharable across number of objects
// efficiently.
type Flyweight struct {
        Data string
}

// FlyweightFactory is the factory that creates and caches the Flyweight objects
type FlyweightFactory struct {
        pool map[string]*Flyweight
}

// NewFlyweightFactory creates the new factory object
func NewFlyweightFactory() *FlyweightFactory {
        return &FlyweightFactory{
                pool: make(map[string]*Flyweight),
        }
}

func (f *FlyweightFactory) GetFlyweight(name string) *Flyweight {
        flyweight, okay := f.pool[name]
        if !okay {
                flyweight = &Flyweight{
                        Data: name,
                }
                time.Sleep(5 * time.Second)
                fmt.Printf("APP - taken 5 seconds to create one \n")
                f.pool[name] = flyweight
        }
        return flyweight
}

// client
func main() {
        f := NewFlyweightFactory()
        o1 := f.GetFlyweight("alice")
        fmt.Printf("o1 Data: %v\n", o1.Data)
        o2 := f.GetFlyweight("bruce")
        fmt.Printf("o2 Data: %v\n", o2.Data)
        o3 := f.GetFlyweight("alice")
        fmt.Printf("o3 Data: %v\n", o3.Data)
        o4 := f.GetFlyweight("alice")
        fmt.Printf("o4 Data: %v\n", o4.Data)
}

// Output:
// APP - taken 5 seconds to create one 
// o1 Data: alice
// APP - taken 5 seconds to create one 
// o2 Data: bruce
// o3 Data: alice
// o4 Data: alice

Notice that when the data structure is large that it takes 5 seconds to create one. On the first attempt to create alice and bruce objects, the notice where 5 seconds has taken shown up. However, the subsequent alice objects are a lot faster thanks to the factory's flyweight caching mechanism. This way, it speeds up the object design creation at the expense of caching memory space.

Expected Outcome (Consequences)

  • Object creation is faster for large data structure and data set.
  • More memory is used for caching.