Design Pattern

Flyweight Pattern

Clean Java-only production-ready implementation.


When you have a large number of fine-grained objects that share common (intrinsic) state. Instead of each object storing the same data, share the intrinsic state across instances.

// ─── EXAMPLE 1 ──────────────────────────────────────────────────────────────
// WHAT WE ARE IMPLEMENTING:
// A rendering system for forest simulations displaying millions of tree
// instances.
//
// WHERE THE FLYWEIGHT FITS IN:
// TreeModel is the shared Flyweight (intrinsic color/texture). Tree holds
// extrinsic individual data (coordinates x, y). TreeFactory manages flyweight
// reuse.
// ────────────────────────────────────────────────────────────────────────────
// --- Flyweight (shared intrinsic state) ---
class CharacterGlyph {
    private final char character;        // Intrinsic: shared across all instances of 'A'
    private final String fontFamily;
    private final int fontSize;

    public CharacterGlyph(char character, String fontFamily, int fontSize) {
        this.character = character;
        this.fontFamily = fontFamily;
        this.fontSize = fontSize;
    }

    public void render(int x, int y, String color) {  // Extrinsic state passed in
        System.out.println("  Render '" + character + "' at (" + x + "," + y + ") font=" + fontFamily + "/" + fontSize + " color=" + color);
    }
}

// --- Flyweight factory ---
class GlyphFactory {
    private final java.util.Map<String, CharacterGlyph> pool = new java.util.HashMap<>();

    public CharacterGlyph getGlyph(char c, String fontFamily, int fontSize) {
        String key = c + ":" + fontFamily + ":" + fontSize;
        return pool.computeIfAbsent(key, k -> new CharacterGlyph(c, fontFamily, fontSize));
    }

    public int poolSize() { return pool.size(); }
}

public class Main {
    public static void main(String[] args) {
        GlyphFactory factory = new GlyphFactory();

        // Render "HELLO" — 5 characters, but 'L' appears twice (shared)
        String text = "HELLO";
        int x = 0;
        for (char c : text.toCharArray()) {
            CharacterGlyph glyph = factory.getGlyph(c, "Arial", 12);
            glyph.render(x, 0, "black");
            x += 10;
        }

        System.out.println("Pool size: " + factory.poolSize() + " (instead of " + text.length() + ")");
    }
}