We continue a look at the structural patterns with a stop at the flyweight. This pattern is one I find ignored more often than it should be. In particular, the large number of data items we typically model in modern applications are often best handled through this pattern.
As always, we will start with the "Gang of Four" intent to set the stage for our discussion.
"Use sharing to support large numbers of fine-grained objects efficiently."
Short and sweet. This intent is to model large collections in the best way based on data needed and memory considerations. A flyweight is an object-oriented approach to data modeling that is practically an index. We only keep up with the data we need for each element. This approach reduces the overhead of moving around fully defined objects.
The flyweight implementation is a smallish class. The typical approach is for a flyweight to be based on a larger class. Then it simply ignores many of the attributes. It often will have the bare minimum of attributes required to implement common interfaces. It might even provide a method to return a complete, and populated instance.
If this sounds familiar, then that is because the flyweight pattern is often used to implement lazy loading. The difference in lazy loading is that those objects sometimes have all of the class properties. However, they do not populate the values immediately. A true use of this pattern does not carry that overhead. This factor is critical when you consider the possibility of thousands, millions, or more instances of a class. At that point, every property, every byte counts.
As mentioned before, a flyweight is just an approach to a class. Thus, there is no need for a language to support any special object-oriented features. Even inheritance is not a requirement for a flyweight. When it is implemented it just needs to be able to handle requests that can be made on a full object. This might even include going out to populate values that are not populated or retrieve a property value temporarily.
In the end, the flyweight pattern is one you should keep in mind in situations where a large number of instances may occur at any one time. Common examples of this include classes that model rows in a database, images in a library or even points on a map.