Flyweight Design Pattern

We often encounter a situation where we need to create too many instances of a given class. If such an object is complex , and its creation requires a lot of computation, this can create performance issues and also risk an out of memory exception. The flyweight pattern tries to avoid this scenario.

The flyweight pattern tries to reduce the number of objects by "reusing" a single instance of the class. That is, it creates a single instance of each type of class and passes a reference to any client that needs to use it.

But this is not so easy to implement. For it to work properly, we need to ensure a few aspects of the code. The foremost requirement is that the objects of the given class should be immutable - that is, the internal state of the object should not change once the object is created.

This is required, because if we have multiple clients using it simultaneously, we do not want to land in a situation where two clients are trying to update it simultaneously. This can get even more complex if we have multi-threading. But even in a single thread operation, we can have the client code using two references to the same object - where updates to one will impact the other invocation.

One might say what is the point if we do not allow the object to change its state. We want the object to track a state as it works. We can't have all the invocations to return the same result!

That is true. In order to use the flyweight pattern, we need to split the class into intrinsic state and extrinsic state. The intrinsic state is the immutable state of the object that is tracked within the object. The extrinsic state is specific to the client invocation and is tracked by the client. Each method invocation takes this extrinsic state as an input parameter and works accordingly. The method invocation alters the extrinsic state and not the intrinsic state. Hence the object remains immutable.

That leads to another question - what is the meaning in having an extrinsic state? If we separate the method and the state, we are violating the fundamental principle of object oriented programming. That is right. If the extrinsic state is a major component of the object state, there is no point in using the flyweight pattern. But if the intrinsic state is much more intricate and heavier than the extrinsic state, it makes sense to keep the extrinsic state away from the object.

The flyweight pattern has the following roles:

  • Instance objects: The individual objects of the required intrinsic state.
  • Factory: The class that takes care of instantiating the required objects. Typically it owns a map with keys to identify the individual objects that are the values. It instantiates the particular object with the required intrinsic configuration and puts it into the map - only when required. It may have a few instances of the same class - for different intrinsic configurations. But, one must be careful if we end up with too many of these instances, we will be violating the principle of flyweight pattern. Of course, the factory should export methods to get a reference of the individual objects using an interface.
  • Client: The client is the code that uses these objects. It invokes methods on the factory object to get a reference to the configured object. Then it invokes individual methods in the configured object, along with the required extrinsic state that it maintains - to achieve the required functionality.