The Flyweight pattern is a structural pattern that is used to minimise memory usage or computational expenses by sharing as much data as possible with similar objects. It achieves this by separating intrinsic (shared) and extrinsic (unique) state, and reusing existing flyweight objects instead of creating new ones.

Applicability

  • When an application needs to create a large number of similar objects
  • When memory footprint is a concern due to repeated or redundant object data
  • When object instances share common data that can be externalised and reused

Pros and Cons

Advantages

  • Memory-efficient
    • By sharing intrinsic state across many objects, memory consumption is significantly reduced
  • Improves performance in high-volume systems
    • Reuse avoids frequent object creation and garbage collection, especially in systems like graphics rendering, text editors, or simulations
  • Supports large numbers of fine-grained objects efficiently
    • Enables creation of seemingly many objects while actually sharing existing instances

Drawbacks

  • Increased complexity
    • Managing extrinsic and intrinsic state separation can complicate the system.
  • Requires careful external management
    • Extrinsic state must be stored and passed in by the client at runtime.
  • Hard to debug
    • Shared state can introduce subtle bugs if not used carefully, especially in multi-threaded environments.

Approach

  1. Define a Flyweight interface to declare operations.
  2. Create Concrete Flyweight classes that implement the flyweight interface and store intrinsic (shared) state.
  3. Use a Flyweight Factory to create and manage flyweight instances. Reuse existing instances if possible.
  4. The Client passes in extrinsic state to flyweight methods, as it is not stored inside the shared object.

Components

  • Flyweight (interface)
    • Declares an operation that accepts extrinsic state.
  • ConcreteFlyweight
    • Implements the Flyweight interface and stores intrinsic state.
  • FlyweightFactory
    • Creates and manages flyweight objects and ensures reuse.
  • Client
    • Maintains extrinsic state and uses flyweights through the factory.

Example

Let’s say we want to draw lots of circles in different positions but with limited colours. The colour is shared (intrinsic), and the position (x, y) is passed in (extrinsic).

Flyweight

interface Shape {
    void draw(int x, int y);
}

Concrete Flyweight

class Circle implements Shape {
    private final String color; // intrinsic (shared)
 
    public Circle(String color) {
        this.color = color;
    }
 
    @Override
    public void draw(int x, int y) {
        System.out.println("Drawing a " + color + " circle at (" + x + ", " + y + ")");
    }
}

Flyweight factory

class ShapeFactory {
    private static final Map<String, Shape> circleMap = new HashMap<>();
 
    public static Shape getCircle(String color) {
        Shape circle = circleMap.get(color);
 
        if (circle == null) {
            circle = new Circle(color);
            circleMap.put(color, circle);
            System.out.println("Created a new " + color + " circle.");
        }
        return circle;
    }
}

Client

Assign random colours and positions.

public class FlyweightExample {
    private static final String[] colors = {"Red", "Green", "Blue", "Yellow"};
 
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            String color = colors[i % colors.length];
            Shape circle = ShapeFactory.getCircle(color);
            int x = (int) (Math.random() * 100);
            int y = (int) (Math.random() * 100);
            circle.draw(x, y);
        }
    }
}
Created a new Red circle.
Drawing a Red circle at (12, 53)
Created a new Green circle.
Drawing a Green circle at (32, 11)
...
Drawing a Red circle at (87, 24)   // Reused the existing Red circle

Back to parent page: Structural Patterns

Design_Pattern Structural_Design_Patterns Flyweight_Pattern SOFT3202