Structural PatternADVANCED7 min deep dive

Flyweight Pattern Pattern

Fits 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.

Real-World Mental Model / Metaphor:

Rendering 1,000,000 trees in a video game forest. Rather than loading the 3D mesh and texture 1,000,000 times, you share 1 TreeType in RAM and only store unique (X, Y) coordinates for each tree.

Interactive Runtime Simulator

Test and tweak inputs dynamically

Interactive Flyweight Pattern SimulatorLIVE PLAYGROUND

Interact with the controls below to see how this design pattern executes in memory at runtime.

Category: Structural
Switch Target Factory Platform:
The client code only interacts with GUIFactory.createButton() and GUIFactory.createCheckbox(). It never couples directly to concrete classes!
CONCRETE PRODUCTS CREATEDmac
Rendered Button:Rendered Checkbox:
The Problem It Solves

Running out of RAM (Out of Memory) when instantiating millions of small objects that duplicate heavy immutable data.

The Architectural Solution

Separate Intrinsic State (shared, constant, read-only) from Extrinsic State (unique, contextual, passed via method arguments).

Pattern Structure & Participants

ParticipantRole & ResponsibilityType
TreeType (Flyweight)Shared intrinsic state (name, color, 3D texture)class
Tree (Context)Extrinsic state (X, Y coordinates + reference to TreeType)class
TreeFactoryCaches and returns existing TreeType instancesclass
Collaboration Rules:
  • 1,000,000 Trees share only 3 TreeType instances in memory
  • RAM usage drops from 2GB to 15MB

Production Code Implementation

Flyweight Pattern.java
// Intrinsic State (Shared in RAM)
public class TreeType {
    private final String name;
    private final String color;
    private final byte[] texture3D; // 10MB texture

    public TreeType(String name, String color, byte[] texture3D) {
        this.name = name;
        this.color = color;
        this.texture3D = texture3D;
    }

    public void draw(int x, int y) {
        System.out.println("Drawing " + name + " at coords (" + x + ", " + y + ")");
    }
}

// Flyweight Factory (Cache)
public class TreeFactory {
    private static final Map<String, TreeType> cache = new HashMap<>();

    public static TreeType getTreeType(String name, String color) {
        String key = name + "_" + color;
        return cache.computeIfAbsent(key, k -> new TreeType(name, color, new byte[1024]));
    }
}

// Extrinsic State (Context)
public class Tree {
    private final int x;
    private final int y;
    private final TreeType type; // Shared reference

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

    public void draw() { type.draw(x, y); }
}
When to Use:
  • •Only when your program must spawn a huge number of similar objects that exhaust available RAM.
When to Avoid (Anti-Pattern):
  • •When memory is not a bottleneck (Flyweight introduces code complexity and minor CPU overhead).

Staff Engineering Interview Insights & Gotchas

  • Mention `Integer.valueOf(100) == Integer.valueOf(100)` returning `true` because of the JVM Integer cache flyweight (-128 to 127).