0 XP · 0 scenes

Flyweight

Share the common part of many similar objects
The problem

A forest of a million trees where every Tree holds its own copy of the heavy mesh and texture.

The idea

Split each object into a shared, unchanging part (TreeType) and a tiny personal part (position).

Reach for it when

Huge numbers of similar objects exhaust memory

1

The picture from life

A printing press has one metal block for each letter, and uses the same block for every "e" on the page. It does not make a new "e" for every occurrence. The block (shared) is separate from where it is placed on the page (individual).

2

The problem

What goes wrong when you do not use it.

A forest of a million trees where every Tree holds its own copy of the heavy mesh and texture. Memory explodes even though there are only two kinds of tree.

✗ Before
tree 1x, yname: oakcolor: greentexture: 2 MBtree 2x, yname: oakcolor: greentexture: 2 MB… tree 1000same heavy dataagain and again
Each tree carries its own copy of the heavy name, colour and texture. 1000 trees = 1000 copies.
Reach for it when
  • Huge numbers of similar objects exhaust memory
  • Most of each object's data is the same across many
  • The shared part never changes (immutable)
3

The idea

How the pattern fixes it.

Split each object into a shared, unchanging part (TreeType) and a tiny personal part (position). A factory keeps one TreeType per kind and hands out the same one every time.

✓ After
TreeFactoryget(name, color)TreeTypename, colortexture ← sharedtree 1x, ytree 2x, ytree 3x, yonce per kindkindkindkind
  • has a / holds
  • creates
The heavy part is shared. Each tree keeps only its position and a link to the shared type.

Who is who

TreeType (flyweight)
Shared, immutable: name, color, texture.
TreeFactory
Returns the existing TreeType for a kind or creates it once.
Tree
Holds only x, y and a reference to its TreeType.

Build it in steps

  1. 1Separate shared (intrinsic) from personal (extrinsic) data.
  2. 2Make the shared part immutable.
  3. 3Add a factory that caches by kind.
  4. 4Create objects through the factory.
4

Watch it run

Step through the calls. Tap an arrow to jump to it.

ClientTreeFactoryTreeType1get('oak', 'green')2TreeType('oak', 'green')3type A4get('oak', 'green')5type A (same object)
Step 1/5

Planting the first tree asks the factory for its type.

get('oak', 'green')
5

The code

Python and Java. Try writing the classes yourself from the diagram first.

class TreeType:                              # shared and immutable
    def __init__(self, name, color):
        self.name = name
        self.color = color


class TreeFactory:
    _types = {}

    @classmethod
    def get(cls, name, color):
        key = (name, color)
        if key not in cls._types:                # create each kind only once
            cls._types[key] = TreeType(name, color)
        return cls._types[key]


class Tree:                                      # only the personal part
    def __init__(self, x, y, kind):
        self.x, self.y, self.kind = x, y, kind


def demo():
    forest = [Tree(n, n, TreeFactory.get("oak", "green" if n % 2 else "dark")) for n in range(1000)]
    return len(forest), len(TreeFactory._types), forest[0].kind is forest[2].kind

What you gain

  • Huge memory savings
  • Faster creation: shared parts exist already

What it costs

  • More complex code: two kinds of data to track
  • Shared state must never change

You have already met it in

  • Java's String pool and Integer.valueOf cache for small numbers
  • Game engines sharing meshes and sprites
  • Text editors sharing one glyph per letter

Often mixed up with

  • SingletonSingleton: one object of a class. Flyweight: one shared object per distinct kind.
  • PrototypePrototype makes independent copies; Flyweight shares one instance instead of copying.
6

Make it stick

Render 10,000 characters of text using one Glyph object per distinct letter. Print how many Glyph objects were created.

Confidence