Connect with me
Structural Design Pattern: Flyweight

This article is the series exploring design patterns using the Java programming language. The goal of this series is to help readers develop a solid understanding of design patterns while also sharing real-world examples from actual codebases that make use of these patterns.
In this article, we’ll be discussing the Flyweight pattern.
Symbols for better navigation:
🤔 Hypothetical Scenario/Imagination
⚠️ Warning
👉 Point to note
📝 Common Understanding
Flyweight Pattern
The Flyweight pattern is a structural design pattern that lets you fit more objects into the available amount of memory by sharing common parts of state between multiple objects instead of keeping all of the data in each object.
While the Singleton pattern was created to ensure a single instance of a class exists, the Flyweight pattern was created to handle millions of instances without crashing your memory.
🤔 Imagine you are building a massive multiplayer war game. You have a Particle class to represent bullets, shrapnel, and missile trails. Each particle has coordinates (x, y), a vector (speed), a color, and a specific sprite image (which might be a few kilobytes).
📉 If a battle creates a million particles, and each particle object holds its own copy of the sprite image and color data, your memory will overflow, and the game will crash.
We need a way to create millions of these objects, but share the heavy data (like the image) so it isn’t duplicated many times in memory.
Enter… The Flyweight.
To understand Flyweight, you must separate your object’s data into two types:
- Extrinsic State (Unique): Data that changes for every object (e.g., the x, y coordinates, the current speed). This is context-dependent.
- Intrinsic State (Shared): Data that remains constant and is shared among many objects (e.g., the color of the bullet, the sprite image). This is context-independent.
Recipe to cook the Flyweight Pattern for objects
Any class can be converted to use Flyweight by following these steps:
- Identify the Intrinsic state (heavy, shared data) and remove it from the main class.
- Create a new class (the Flyweight) to store this intrinsic state. Make it immutable.
- Keep the Extrinsic state in the main class (or pass it to methods when needed).
- Create a Factory class to manage a pool of Flyweights.
Case Study
In our example, we will build an Inventory Management System (IMS).
We start with an Item class, which holds intrinsic properties like name and price, data that remains constant across all transactions.
class Item {
String itemName;
Double price;
public Item(String itemName, Double price) {
this.itemName = itemName;
this.price = price;
}
}Next, we introduce an Order class to track the quantity of items purchased.
Since the quantity varies from order to order, this represents the extrinsic state.
class Order {
Item item;
int quantity;
public Order(Item item, int quantity) {
this.item = item;
this.quantity = quantity;
}
}Finally, our main class, InventoryManagementSystem, acts as the factory; it maintains a pool of unique Item objects and facilitates the creation of new orders.
class InventoryManagementSystem {
private Map<String, Item> itemsMap;
private List<Order> orderList;
public InventoryManagementSystem() {
this.itemsMap = new HashMap<>();
this.orderList = new ArrayList<>();
}
public void placeOrder(String itemName, int quantity, double price) {
if (!itemsMap.containsKey(itemName)) {
itemsMap.put(itemName, new Item(itemName, price));
}
orderList.add(new Order(itemsMap.get(itemName), quantity));
}
}
Let’s tie up everything see how things play out.
public class Main {
public static void main(String[] args) {
InventoryManagementSystem ims = new InventoryManagementSystem();
ims.placeOrder("Soap", 2, 12.0);
ims.placeOrder("Shampoo", 1, 110.0);
ims.placeOrder("Bathrobe", 1, 1000.0);
ims.placeOrder("Shampoo", 1, 110.0);
ims.placeOrder("Soap", 1, 12.0);
ims.printOrders();
}
}As you can see, creating multiple orders now does not require us to instantiate different items in the runtime. Rather, multiple orders share the common state values of itemName and price.
Real-World Use Case of Proxy
Here is an example from the real-world code where they have used a Flyweight.
Java String Constant Pool: The implementation of Flyweight in Java is the String class.
When you do this:
String s1 = "Hello";
String s2 = "Hello";Java doesn’t create two separate objects in the memory heap for the text Hello. Inside the JVM, there is a special memory region called the String Constant Pool.
- When
s1is created, the JVM checks the pool. It’s empty, so it creates “Hello” and returns the reference. - When
s2is created, the JVM checks the pool. It finds “Hello” already exists! - It simply returns the reference to the existing object.
Both s1 and s2 point to the exact same memory address. This saves a massive amount of memory in large applications that process text.
Up next in the Series
Bridge Design Pattern
Subscribe to my newsletter today!



