3 min read

Flyweight Pattern

The Flyweight Pattern is a structural design pattern that lets you fit more objects into the available amount of RAM by sharing common parts of state between multiple objects instead of keeping all of the data in each object.

1. The Core Concept

The pattern suggests splitting the state of an object into two parts:

  • Intrinsic State: The data that is constant and shared across many objects (e.g., the texture of a bullet, the font face of a character). This is stored in the Flyweight object.
  • Extrinsic State: The data that is unique to each instance (e.g., the position of a bullet, the size of a character). This is stored in the Context object or passed to methods.

2. Analogy: A Forest in a Game

Imagine rendering a forest with 1,000,000 trees.

  • Bad Approach: Each tree object stores its mesh, texture, color, and position. If the mesh/texture is 10MB, you need terabytes of RAM.
  • Flyweight Approach: You create one TreeType object (Flyweight) that stores the mesh and texture. You create 1,000,000 Tree objects that store just coordinates (x, y) and a reference to the TreeType.

3. Example (TypeScript)

Let's implement the forest example.

// The Flyweight: Stores shared state
class TreeType {
    constructor(
        private name: string,
        private color: string,
        private texture: string
    ) {}

    draw(canvas: any, x: number, y: number): void {
        // Draw the texture at x, y
        console.log(`Drawing ${this.name} tree (${this.color}) at (${x}, ${y})`);
    }
}

// The Flyweight Factory: Manages the pool
class TreeFactory {
    static treeTypes: Map<string, TreeType> = new Map();

    static getTreeType(name: string, color: string, texture: string): TreeType {
        const key = `${name}-${color}-${texture}`;
        if (!this.treeTypes.has(key)) {
            this.treeTypes.set(key, new TreeType(name, color, texture));
            console.log(`Factory: Created new TreeType: ${key}`);
        }
        return this.treeTypes.get(key)!;
    }
}

// The Context: Stores unique state
class Tree {
    constructor(
        private x: number,
        private y: number,
        private type: TreeType
    ) {}

    draw(canvas: any): void {
        this.type.draw(canvas, this.x, this.y);
    }
}

// The Client
class Forest {
    private trees: Tree[] = [];

    plantTree(x: number, y: number, name: string, color: string, texture: string) {
        const type = TreeFactory.getTreeType(name, color, texture);
        const tree = new Tree(x, y, type);
        this.trees.push(tree);
    }

    draw(canvas: any) {
        for (const tree of this.trees) {
            tree.draw(canvas);
        }
    }
}

// Usage
const forest = new Forest();
forest.plantTree(1, 1, "Oak", "Green", "oak.png");
forest.plantTree(2, 5, "Oak", "Green", "oak.png"); // Reuses existing Oak type
forest.plantTree(5, 3, "Pine", "DarkGreen", "pine.png"); // Creates new Pine type

forest.draw("Canvas");

4. Pros and Cons

Pros Cons
RAM Savings: Drastically reduces memory usage when dealing with huge numbers of similar objects. CPU Cost: You might trade RAM for CPU if you have to recalculate extrinsic data constantly.
Complexity: The code becomes much more complicated. New team members might wonder why the state of an entity is separated.

5. Real World Example: String Interning

String Interning is a method of storing only one copy of each distinct string value, which must be immutable. This is a classic implementation of the Flyweight pattern used by languages like Java and Python to save memory.

Java

In Java, string literals are automatically interned in the "String Constant Pool".

String s1 = "Hello";
String s2 = "Hello"; // Reuses the same object from the pool
String s3 = new String("Hello"); // Forces creation of a new object

System.out.println(s1 == s2); // true (Same reference)
System.out.println(s1 == s3); // false (Different references)

Python

Python also interns string literals (especially small ones or identifiers).

a = "hello"
b = "hello"
print(a is b) # True

programming/design-patterns programming/object-oriented-programming