Full Stack • Java • System Design • Cloud • AI Engineering

Flyweight Design Pattern in Java

Learn Flyweight Design Pattern in Java with real-world examples, memory optimization techniques, intrinsic and extrinsic state, UML diagrams, Java implementation, JVM examples, enterprise use cases, and interview questions.

What You Will Learn

In this article, you'll learn:

  • What is Flyweight Pattern?
  • Why Flyweight Pattern is Needed
  • Memory Optimization Concepts
  • Intrinsic vs Extrinsic State
  • UML Diagrams
  • Java Implementation
  • JVM Examples
  • Gaming Examples
  • Enterprise Use Cases
  • Benefits and Limitations
  • Interview Questions

Introduction

Imagine building a game.

The game contains:

100,000 Trees

100,000 Soldiers

100,000 Cars

If every object stores:

Color

Texture

Shape

Coordinates

Size

Memory usage becomes enormous.

Example:

100,000 Trees

×

1 MB Each

=

100 GB Memory

Clearly impossible.

Most tree objects share common information:

Tree Type

Color

Texture

Shape

Only location changes.

Flyweight Pattern solves this problem.


What is Flyweight Pattern?

Flyweight is a Structural Design Pattern that reduces memory usage by sharing common object state among multiple objects.

Instead of creating:

100,000 Separate Objects

we create:

1 Shared Object

+

100,000 References

Purpose of Flyweight Pattern

Primary goal:

Reduce Memory Consumption

Improve Performance

Real World Analogy

Imagine a library.

Without sharing:

Every Student

Gets Their Own Book Copy

Requires thousands of books.

With sharing:

One Book

Used By Many Students

Much more efficient.

This is Flyweight.


Problem Without Flyweight

flowchart TD

A[Tree 1]

B[Tree 2]

C[Tree 3]

D[Tree 100000]

A --> X[Large Memory]

B --> X

C --> X

D --> X

Each object stores duplicate data.


Solution With Flyweight

flowchart TD

A[Shared Tree Object]

B[Position 1]

C[Position 2]

D[Position 3]

E[Position 100000]

B --> A

C --> A

D --> A

E --> A

Common data is shared.


Key Idea

Separate state into:

Intrinsic State

Extrinsic State

Intrinsic State

Shared data.

Stored inside Flyweight.

Examples:

Color

Texture

Shape

Font

Character

Never changes.


Extrinsic State

External data.

Passed from client.

Examples:

X Coordinate

Y Coordinate

Size

Position

Changes per object.


Tree Example

Intrinsic State:

Tree Type

Green Color

Oak Texture

Extrinsic State:

X=100

Y=200

Flyweight Architecture

flowchart LR

Client --> FlyweightFactory

FlyweightFactory --> SharedFlyweight

Client --> ExtrinsicState

Components

Flyweight

Shared object.


Concrete Flyweight

Stores intrinsic state.


Flyweight Factory

Creates and reuses objects.


Client

Provides extrinsic state.


UML Diagram

classDiagram

class Flyweight {
  +display(x,y)
}

class ConcreteFlyweight

class FlyweightFactory

class Client

Flyweight <|-- ConcreteFlyweight

FlyweightFactory --> ConcreteFlyweight

Client --> FlyweightFactory

Gaming Example

Suppose game has:

100000 Trees

Without Flyweight:

100000 Objects

With Flyweight:

1 Tree Type Object

100000 Locations

Step 1: Flyweight Interface

public interface Tree {

    void display(
            int x,
            int y);
}

Step 2: Concrete Flyweight

public class OakTree
        implements Tree {

    private final String color;

    private final String texture;

    public OakTree() {

        this.color = "Green";

        this.texture = "Oak";
    }

    @Override
    public void display(
            int x,
            int y) {

        System.out.println(
                "Tree at "
                        + x
                        + ","
                        + y);
    }
}

Step 3: Flyweight Factory

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

public class TreeFactory {

    private static final Map<
            String,
            Tree> cache =
            new HashMap<>();

    public static Tree getTree(
            String type) {

        if (!cache.containsKey(type)) {

            cache.put(
                    type,
                    new OakTree());
        }

        return cache.get(type);
    }
}

Step 4: Client Code

public class FlyweightDemo {

    public static void main(
            String[] args) {

        for (int i = 0;
             i < 5;
             i++) {

            Tree tree =
                    TreeFactory.getTree(
                            "OAK");

            tree.display(
                    i * 10,
                    i * 20);
        }
    }
}

Output

Tree at 0,0

Tree at 10,20

Tree at 20,40

Tree at 30,60

Tree at 40,80

Only one Tree object exists.


Execution Flow

sequenceDiagram

Client->>Factory:getTree("OAK")

Factory->>Cache:Check Existing

Cache-->>Factory:Return Object

Factory-->>Client:Shared Tree

Client->>Tree:display(x,y)

Memory Comparison

Without Flyweight:

100000 Trees

×

1 MB

=

100 GB

With Flyweight:

1 Shared Tree

+

Coordinates

≈ Few MB

Huge savings.


JVM Example

Java String Pool is a Flyweight Pattern.

Example:

String s1 = "JAVA";

String s2 = "JAVA";

Memory:

One String Object

Shared by both references.


String Pool Diagram

flowchart TD

A[s1]

B[s2]

A --> C["JAVA"]

B --> C

Integer Cache Example

Integer a = 100;

Integer b = 100;

JVM reuses cached objects.

Flyweight in action.


Database Connection Pool

Connections are expensive.

Instead of:

New Connection Per Request

Use:

Shared Connection Pool

Similar concept.


Logging Framework Example

Loggers are often reused.

Logger logger =
        LoggerFactory
                .getLogger(
                        MyClass.class);

Shared instances reduce memory.


Enterprise Examples

Banking

Currency objects:

USD

EUR

INR

Shared across transactions.


Insurance

Policy templates.

Shared by millions of customers.


Gaming

Trees

Cars

Buildings

Characters

Shared models.


Text Editors

Characters:

A

B

C

Shared fonts and styles.


Benefits

✅ Significant Memory Reduction

✅ Better Performance

✅ Faster Object Creation

✅ Reuse Existing Objects

✅ Improved Scalability


Limitations

❌ Increased Complexity

❌ Difficult State Management

❌ Extrinsic State Must Be Managed Carefully

❌ Debugging Can Be Harder


When To Use

Use Flyweight when:

  • Large number of similar objects exist
  • Memory is a concern
  • Object creation is expensive
  • Shared state is possible

When Not To Use

Avoid Flyweight when:

  • Object count is small
  • Memory is not an issue
  • Shared state does not exist

Flyweight vs Singleton

Feature Flyweight Singleton
Instances Many Shared Objects One Object
Purpose Save Memory Global Access
Scope Object Pool Single Instance

Flyweight vs Prototype

Feature Flyweight Prototype
Goal Reuse Objects Clone Objects
Memory Shared New Copies
Focus Optimization Object Creation

Real Enterprise Architecture

flowchart LR

Client

--> FlyweightFactory

FlyweightFactory

--> SharedObjects

SharedObjects

--> MemoryOptimization

Interview Questions

What is Flyweight Pattern?

A structural design pattern used to reduce memory usage by sharing common object state.


What Problem Does It Solve?

Memory consumption caused by large numbers of similar objects.


What is Intrinsic State?

Shared state stored inside Flyweight objects.


What is Extrinsic State?

External state provided by the client.


Real Java Example?

String Pool.


Real Enterprise Example?

Database Connection Pooling.


Difference Between Flyweight and Singleton?

Flyweight manages many shared objects.

Singleton manages one object.


Key Takeaways

  • Flyweight is a Structural Design Pattern.
  • Reduces memory usage through object sharing.
  • Separates Intrinsic and Extrinsic State.
  • Widely used in JVM internals.
  • String Pool is the most common Java example.
  • Excellent for gaming, caching, pooling, and large-scale systems.
  • Improves performance and scalability significantly.