Learn the Flyweight Design Pattern
This is the 10th post in a series on design patterns.
Flyweight is a structural design pattern that lets you fit more objects into the available amount of RAM by sharing common parts of the state between multiple objects instead of keeping all of the data in each object.
Imagine that you have developed an online platform that lets users name a star and that platform gives them lifetime ownership of it for a small fee.
That sounds like a great business idea!
The platform was working fine until it was not very popular, but now you start to see that the platform cannot handle the growing numbers of stars in the sky. Upon debugging, you found that the platform crashed because of insufficient RAM.
Now you can either vertically or horizontally scale your system to support more users, but wait for a second, there is a cost involved.
Could our design be improved so that RAM usage is reduced? This is where the Flyweight design pattern comes into play.
Flyweight Design Pattern
You discovered that the Star class attributes like size, color, brightness, and sprite consume a lot of memory. What is actually worse is that these fields store data nearly identical across multiple stars. Additionally, each star has its own coordinates and name.
An object’s constant data is called its intrinsic state. It exists within the object; other objects can only read and not change it. It is the rest of an object’s state that is often altered by other objects from the outside, known as the extrinsic state.
According to the Flyweight pattern, you should stop storing the extrinsic state inside the object. You should instead pass this state to specific methods that depend on it. Only the intrinsic state remains in the object, allowing it to be reused in multiple contexts. As a result, you would need fewer of these objects since they differ only in their intrinsic state, which has far fewer variations than their extrinsic state.
The Flyweight pattern is nothing more than an optimization. You must ensure that your program does have the RAM consumption issue caused by having a large number of similar objects in memory at the same time.
UML Class Diagram
Not familiar with UML Class Diagram? I have written a detailed post on the UML Class diagram.
Implementation steps
- Divide fields of a class that will become a flyweight into two parts:
* Intrinsic state — The fields that contain unchanging data duplicated across many objects.
* Extrinsic state — The fields that contain contextual data unique to each object. - Make sure the fields that represent the intrinsic state are immutable in the class. They must only be initialized in the constructor.
- Examine methods that use extrinsic state fields. Introduce a new parameter for each field used in the method.
- You can also create a factory class to manage the pool of flyweights. It should check if a flyweight already exists before creating a new one. Once the factory is operational, clients can only request flyweights through it. Bypassing the flyweight’s intrinsic state, they should describe the desired flyweight to the factory.
- For flyweight objects to be called, the client must store or calculate values of the extrinsic state (context).
Source Code Implementation
StarType(Flyweight) class holds the portion of the Star object’s state that can be shared among multiple stars. The same StarType object can be used in numerous contexts.
Star(Context) class contains the extrinsic state, unique to all-stars, such as x, y, and name. When paired with a StarType object, a context represents the full state of the Star object.
The StartTypeFactory (Flyweight Factory) class maintains a pool of existing flyweights. Clients do not need to create flyweights directly. Rather, they call the factory and send bits of the desired flyweight’s intrinsic state. It looks through previously created flyweights and either return one that matches search criteria or creates a new one if none is found.
In the sky(Client) class, the star is named and drawn.
// Output StarType [brightness=1110, color=HALO, size=11230, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]Creating new StartType StarType [brightness=2220, color=SILVER, size=23232, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]Creating new StartType >>> StarType [brightness=1110, color=HALO, size=11230, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]Already available in cache StarType [brightness=3330, color=SILVER, size=11230, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]Creating new StartType StarType [brightness=1110, color=HALO, size=23232, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]Creating new StartType >>> StarType [brightness=2220, color=SILVER, size=23232, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]Already available in cache >>> StarType [brightness=1110, color=HALO, size=11230, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]Already available in cache StarType [brightness=1110, color=HALO, size=11230, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] named ABC Star drawn on the sky at coordinates(10,0) StarType [brightness=2220, color=SILVER, size=23232, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] named HHHG Star drawn on the sky at coordinates(20,0) StarType [brightness=1110, color=HALO, size=11230, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] named BHUG Star drawn on the sky at coordinates(30,0) StarType [brightness=3330, color=SILVER, size=11230, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] named JKUIU Star drawn on the sky at coordinates(40,0) StarType [brightness=1110, color=HALO, size=23232, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] named JKHG Star drawn on the sky at coordinates(50,0) StarType [brightness=2220, color=SILVER, size=23232, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] named HIGH Star drawn on the sky at coordinates(60,0) StarType [brightness=1110, color=HALO, size=11230, sprite=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] named HJHJK Star drawn on the sky at coordinates(70,0)
When To Apply Flyweight Design Pattern
- Only use the Flyweight design pattern when your program must support a large number of objects that barely fit in RAM.
Pros of Flyweight Design Pattern
- If your program has tons of similar objects, you can save a lot of RAM.