AlgoMaster Logo

Flyweight Design Pattern

Ashish

Ashish Pratap Singh

5 min read

The Flyweight Design Pattern is a structural pattern that focuses on efficiently sharing common parts of object state across many objects to reduce memory usage and boost performance.

It’s particularly useful in situations where:

  • You need to create a large number of similar objects, but most of their data is shared or repeated.
  • Storing all object data individually would result in high memory consumption.
  • You want to separate intrinsic state (shared, reusable data) from extrinsic state (context-specific, passed in at runtime).

When building high-volume systems like text editors (with thousands of character glyphs), map applications (with repeated icons or tiles), or game engines (with many similar objects like trees or particles), developers often instantiate huge numbers of objects many of which are functionally identical.

But this can lead to significant performance issues, excessive memory allocation, and poor scalability especially when most of these objects differ only by a few small, context-specific values.

The Flyweight Pattern solves this by sharing common state (the intrinsic part) across all similar objects and externalizing unique data (the extrinsic part). It allows you to create lightweight objects by caching and reusing instances instead of duplicating data.

Let’s walk through a real-world example to see how we can apply the Flyweight Pattern to drastically reduce memory usage and create scalable object-heavy systems.

1. The Problem: Rendering Characters

Imagine you're building a rich text editor that needs to render characters on screen — much like Google Docs or MS Word.

Every character (abc...z, punctuation, etc.) must be displayed with formatting information such as:

  • Font family
  • Font size
  • Color
  • Style (bold, italic, etc.)
  • Position (x, y on the screen)

A naïve implementation might look like this:

Now imagine rendering a 10-page document with 500,000 characters. Even if most characters share the same font, size, and color — you’re still allocating half a million objects, most of which contain duplicate formatting data.

Why This Is a Problem

1. High Memory Usage

Each character glyph holds repeated data (font, size, color) — even though these are shared across thousands of characters. You're wasting memory by storing the same values over and over.

2. Performance Bottleneck

Creating and managing a massive number of objects increases GC pressure, reduces cache performance, and may cause your app to lag on lower-end machines.

3. Poor Scalability

Want to render an entire book or open multiple large documents? Memory usage will balloon out of control, and you'll hit limits quickly.

What We Really Need

We need a way to:

  • Share the formatting data (font, size, color, etc.) among all similar characters
  • Only store what's truly unique (like position or context) for each character
  • Avoid duplicating redundant data while still rendering characters accurately

This is where the Flyweight Pattern comes in.

2. What is the Flyweight Pattern

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

Instead of creating a new object for every instance — even when the data is the same — the Flyweight Pattern allows you to reuse shared objects (called flyweights) and externalize the state that differs between them.

Class Diagram

Flyweight Interface

Declares a method like draw(x, y) that takes extrinsic state (position)

ConcreteFlyweight

Implements the flyweight and stores intrinsic state like font and symbol

FlyweightFactory

Caches and reuses flyweights to avoid duplication

Client

Maintains extrinsic state and uses shared flyweights to perform operations

3. Implementing Flyweight

Let’s implement the Flyweight Pattern to optimize how we render text in a document editor. Our goal is to share common formatting properties (font, size, color) across characters and store only unique data (like position) at the instance level.

1. Define the Flyweight Interface

The flyweight interface declares a method like draw(x, y) that renders a character on screen.

Importantly, the flyweight does not store extrinsic state (like position). Instead, this data is supplied by the client at runtime.

Each flyweight object represents shared formatting (intrinsic state), but it expects position to be passed in when drawn.

2. Implement the Concrete Flyweight

This class holds the intrinsic state — the shared, repeatable properties like:

  • The character itself (e.g., 'A')
  • Font family
  • Font size
  • Font color

All glyphs with the same combination of character, font, size, and color can reuse the same CharacterGlyph instance.

3. Create the Flyweight Factory

The factory ensures flyweights are shared and reused. It checks whether a flyweight with a given set of intrinsic values already exists and returns it, or creates a new one if it doesn't.

This factory is the heart of memory optimization. It ensures no duplicate formatting objects are created.

4. Create the Client

The client is responsible for rendering the document. It:

  • Retrieves flyweight objects from the factory
  • Combines each flyweight with position-specific data (extrinsic state)
  • Stores RenderedCharacter objects that contain a flyweight and coordinates

5. Test it in the Main Method

Finally, let’s use the system to render two words, each with different formatting:

Sample Output

Only 8 shared glyphs were created, even though we rendered 10 characters — memory-efficient and scalable!

What We Achieved

  • Memory efficiency: Shared formatting data eliminates duplication
  • Improved performance: Fewer objects = faster rendering and lower GC pressure
  • Separation of concerns: Formatting logic and position/context are cleanly separated
  • Reusability: Glyphs for common characters are reused across the document
  • Scalability: Can handle thousands of characters with minimal memory footprint