Patterns: composition · 3 MIN READ

Flyweight: share immutable intrinsic state

Separate reusable data from per-use context before optimizing memory.

Separate reusable data from per-use context before optimizing memory. Flyweight shares intrinsic state across many logical objects while callers supply extrinsic context. Trace the worked Go example, then compare the benefit with the cost before applying this design to your own project.

Structural pattern · A MAP OF THE IDEA

  1. Catalog reuses one intrinsic glyph
  2. Placement supplies external position
  3. Many logical uses share immutable data

Useful when

  • Many objects repeat sizable immutable data
  • Extrinsic state can stay at each call site

Watch out

  • Intern tables can retain unused data
  • Mutable shared state breaks independence

Implementation & operation cost: Medium

Fit depends on the task

Small tool or CLI2/5
Domain-rich application3/5
Independent distributed services3/5

Editorial suitability, not benchmarks or a universal ranking. Styles describe different axes and can be combined.

01

The design decision

Flyweight shares intrinsic state across many logical objects while callers supply extrinsic context. A glyph shape can be shared while its position belongs to each placement. The optimization is useful only when repeated retained data is large enough to matter.

02

A complete Go example

Read this program from the entry point and follow the calls shown in the diagram. The output is included at the end so you can check the behavior without a compiler.

go
package main

import (
	"fmt"
)

type Glyph struct{ shape string }
type Catalog struct{ glyphs map[string]*Glyph }

func (c *Catalog) Get(shape string) *Glyph {
	if g := c.glyphs[shape]; g != nil {
		return g
	}
	g := &Glyph{shape: shape}
	c.glyphs[shape] = g
	return g
}

type Placement struct {
	Glyph *Glyph
	X     int
}

func main() {
	c := Catalog{glyphs: make(map[string]*Glyph)}
	a := Placement{Glyph: c.Get("G"), X: 1}
	b := Placement{Glyph: c.Get("G"), X: 8}
	fmt.Println(a.Glyph == b.Glyph, a.X, b.X)
}

// Output:
// true 1 8
Read the code

Two placements share the same Glyph pointer but retain different positions. Treat shape as immutable after registration. The map is owned by one goroutine here; sharing Catalog concurrently would require synchronization or immutable publication.

03

Tradeoffs and the simpler alternative

An unbounded intern table can retain data forever and consume more memory than it saves. Measure object counts and retained size, bound the cache where necessary, and do not share mutable per-use fields such as selection or position inside the flyweight.

TAKE THIS WITH YOU

Shares immutable intrinsic state across many uses. An unbounded intern table can retain data forever and consume more memory than it saves. Measure object counts and retained size, bound the cache where necessary, and do not share mutable per-use fields such as selection or position inside the flyweight.

Check your understanding

Which statement best describes Flyweight: share immutable intrinsic state?

Go to the source

Progress stays in this browser. No account needed.