Java 4 min read

The Flyweight Design Pattern: Share to Save Memory

Master the Flyweight Pattern in Java. Learn how to support thousands of objects efficiently by sharing common state.

MR

Moshiour Rahman

Advertisement

The Problem: Memory Explosion

Imagine a game with 1 million trees. Each tree has:

  • Intrinsic state (shared): treeType, texture, model (2MB each)
  • Extrinsic state (unique): x, y coordinates (8 bytes)

Naive approach:
1 million trees × 2MB = 2,000 GB of RAM 💥

But there are only 5 tree types. Why store the same texture 200,000 times?

The Solution: The Flyweight Pattern

The Flyweight Pattern minimizes memory by sharing as much data as possible with similar objects.

Real-Life Analogy: Chess Pieces ♟️

In a chess game:

  • Shared (Intrinsic): Icon image, movement rules (same for all white pawns)
  • Unique (Extrinsic): Current position on board

Instead of storing the icon 8 times for 8 pawns, share one icon and store only positions.

Visualizing the Pattern

Flyweight Pattern

Implementation

1. The Flyweight Class (Immutable Shared Object)

// Flyweight: Stores intrinsic (shared) state
public class TreeType {
    private final String name;
    private final String color;
    private final String texture; // Large data (2MB)

    public TreeType(String name, String color, String texture) {
        this.name = name;
        this.color = color;
        this.texture = texture;
    }

    public void render(int x, int y) {
        System.out.println("Rendering " + name + " at (" + x + ", " + y + ")");
        // Use shared texture
    }
}

2. The Flyweight Factory (Pool)

import java.util.HashMap;
import java.util.Map;

public class TreeFactory {
    private static final Map<String, TreeType> treeTypes = new HashMap<>();

    public static TreeType getTreeType(String name, String color, String texture) {
        String key = name + color;

        if (!treeTypes.containsKey(key)) {
            treeTypes.put(key, new TreeType(name, color, texture));
            System.out.println("Created new TreeType: " + key);
        }
        return treeTypes.get(key);
    }
}

3. Context Object (Stores Extrinsic State)

// Context: Stores extrinsic (unique) state
public class Tree {
    private int x, y; // Unique
    private TreeType type; // Shared (flyweight)

    public Tree(int x, int y, TreeType type) {
        this.x = x;
        this.y = y;
        this.type = type;
    }

    public void render() {
        type.render(x, y); // Pass extrinsic state
    }
}

Usage

TreeFactory factory = new TreeFactory();

// Create 1 million trees with only 5 tree types
List<Tree> forest = new ArrayList<>();

for (int i = 0; i < 1_000_000; i++) {
    int x = random.nextInt(10000);
    int y = random.nextInt(10000);

    String[] types = {"Oak", "Pine", "Birch", "Maple", "Spruce"};
    String treeType = types[random.nextInt(5)];

    TreeType sharedType = TreeFactory.getTreeType(treeType, "Green", "texture.png");
    forest.add(new Tree(x, y, sharedType));
}

// Memory used:
// - 5 TreeType objects (5 × 2MB = 10MB)
// - 1M Tree objects (1M × 16 bytes = 16MB)
// Total: ~26MB instead of 2,000GB!

In The Wild (Real World Examples)

1. String Pool in Java

The most famous flyweight!

String s1 = "Hello"; // Goes to string pool
String s2 = "Hello"; // Reuses from pool

System.out.println(s1 == s2); // true (same object!)

2. Integer.valueOf() Cache

Java caches integers from -128 to 127:

Integer a = Integer.valueOf(100);
Integer b = Integer.valueOf(100);
System.out.println(a == b); // true (cached)

Integer c = Integer.valueOf(200);
Integer d = Integer.valueOf(200);
System.out.println(c == d); // false (not cached, different objects)

3. Font Rendering

GUI frameworks share font objects:

Font arial12 = FontFactory.getFont("Arial", 12);
// Same font object used for all "Arial 12" text

When to Use Flyweight

Use when:

  • Large number of similar objects
  • Most state can be extrinsic (pulled out)
  • Object identity doesn’t matter

Don’t use when:

  • Few objects
  • No shared state
  • Object identity is important (need unique instances)

Cheat Sheet

FeatureDetails
CategoryStructural
Problem SolvedMemory overhead from large numbers of objects
Key implementationFactory pool + intrinsic/extrinsic state separation
ProsMemory savings (massive reduction for many objects)
ConsComplexity (state separation), CPU tradeoff (some overhead)

Tips to Remember 🧠

  • “String Pool”: The #1 example every Java developer knows.
  • “Intrinsic = Inside, Extrinsic = External”: Intrinsic is shared inside flyweight, extrinsic is passed from outside.
  • “Factory Pattern”: Flyweight almost always uses a factory to manage the pool.

Advertisement

MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

Moshiour Rahman

Software Architect & AI Engineer

Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.

Related Articles

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.