Adam is a cunning lad. He has been double-dating Elina and Carina. However he has identified himself with different names to each of them. Elina knows him as Adrian and Carina knows him as Boris. Is Adam cheating? Well, Adam begs to differ. He says life is short and he is a limited resource, only one person. Why not have fun with two girls at a time? Inside himself, he is always the same Adam. But he switches to two different personalities for the sake of Elina and Carina, by changing his external behaviour. Morally questionable, no doubt. But he is a fine specimen of the flyweight pattern.
Flyweight pattern in real life
Kalyan railway station, 50 km from Mumbai, is one of the busiest railway stations in India. Nearly 300 inter-city trains (284 to be exact) transit through the railway station’s 8 platforms every day. For each train, an announcement is made before arrival. A typical announcement would be, “12163 down Dadar – Chennai Express is arriving on platform number 5”.
An unoptimised non-flyweight system
Let’s assume that all announcements are made with recorded audio. There are 284 recordings and each of them is associated with a button on a large panel. Let’s assume that each train arrives at a fixed platform every day. Pressing one button will trigger the announcement for that train. So a button named ‘12163’ will trigger the announcement for Dadar – Chennai express arriving on platform 5.
Let’s do some math. It takes 7 seconds to make one train’s announcement. For 284 trains, it’s more than half an hour (33 minutes and 8 seconds to be precise) of audio. That takes a lot of space to store. Is there a way to optimise this? And what happens if platform #5 is occupied by a delayed train some day and Dadar – Chennai express has to be routed to platform #6? The recording on the button is irrelevant and a special manual announcement needs to be made over the PA system. Can we solve this?
Upgraded system with flyweight pattern
Let’s look at the template for an announcement, “<Train number> <up/down> <Train name> is arriving on platform number <platform>”. The section, ‘is arriving on platform number’ repeats for every announcement. That part takes 3 seconds. What if we can record it seperately and trigger it to auto-play after the train number and names are announced?
Here’s an upgraded switch board for the announcer. There are 284 buttons, one for each train and another 8 buttons for the platforms. The announcer needs to press one button for a train and another button for the platform. No announcement is triggered yet, but the two chosen buttons light up. To start the announcement, the announcer needs to press a special ‘Speak’ button. For example, the announcer presses the switch for train 12163, followed by the switch for platform 5 and finally the ‘Speak’ button. That triggers the announcement to start. We hear the sound, “12163 down Dadar – Chennai express”. Next, the system announces the phrase, “is arriving on platform number”, followed by the platform number chosen, i.e. 5. Since the train and the platform have to be chosen individually, it solves the problem for a train with a re-routed platform. But the flyweight system does more. It’s ultimate claim to glory.
In the unoptimised system, all the recordings put together took 33 minutes and 8 seconds. Let’s look at the new system. The first button panel contains 284 buttons. Behind each button is only the numbers and names of trains. Each number and name spoken together takes 3 seconds. For 284 trains, that is 14 minutes and 12 seconds. The phrase “is arriving on platform number” takes another 3 seconds. Each platform number takes one second to say, so 8 platform numbers will occupy 8 seconds of recording time. We have the ingredients for all possible train announcements. And they take only 14 minutes and 23 seconds! That’s a whopping reduction by 56%.
So, what is flyweight pattern?
A flyweight pattern is specifically designed to reduce resource usage by reducing repetition. A good example is the announcement system discussed in the previous example, where one phrase was extracted and saved from repetition. From another point of view, one object can be used in several ways by slightly altering some values around it. Adam is a good example. Even in our announcement system, the phrase “is arriving on platform number” is a single phrase used in 284 different contexts. Call this leverage.
In a flyweight pattern, a resource-hungry object which repeats itself is ‘quarantined’ away. This object has been weighing the whole system down. Seperating it has caused the whole system to be lighter. This quarantined object is called the flyweight. It’s weight was preventing the system from flying higher and scaling the system.
The way to approach a flyweight problem is to look for intrinsic properties and extrinsic properties in the original unoptimised object. The properties which repeat themselves can be extracted into the flyweight. These will be the properties intrinsic to a flyweight. The properties which change everytime, also called extrinsic properties, will remain inside a regular object. To get the intrinsic properties, the regular object will have a reference to the flyweight object. In our announcement system, the end of the announcement of the train number and name automatically triggered the speaking of the ‘arriving’ phrase. This is analogous to the reference from the non-flyweight object to the flyweight object.
Can there be multiple fly-weights in the same system?
Of course, there can. Let’s upgrade Kalyan’s train announcement system. We will have two flyweights: one called ‘expected trains’, which says, “is arriving on platform number” and another one called ‘arrived trains’, which says “has arrived on platform number”. We can even have a third flyweight ‘departing trains’ that says “is shortly leaving from platform number”.
How can the operator control which flyweight to use? He has a knob on the control panel that he can turn towards the required flyweight. After the train number and name have been announced, the knob controls which common phrase to use. In the parlance of design patterns, this knob is called the flyweight factory. The factory’s job is to return the required flyweight object when asked for. The factory makes it possible to store multiple flyweights in the system and request for one. These flyweights are then combined with extrinsic properties to create a large combinations of non-flyweight objects.
Here is a diagram of the flyweight pattern, using multiple flyweight objects and a factory.
Flyweight pattern in software
Video games are one of the grandest examples of the flyweight pattern. Imagine a war game in which the following can be fired from different guns: 0.2 calibre bullets, 0.45 calibre bullets and sniper projectiles. Each one is represented by images of various sizes. Let’s say that the game is getting frenzied and that on the screen, 15 pieces of 0.2s, 12 pieces or 0.45s and 8 sniper projectiles are being fired. Would you load the image files that may times?
No, of course not. You’d load each image exactly once and create flyweight objects. Depending on the gun that was fired, a flyweight factory determines which image is to be used. The point on the screen where that image is to be drawn changes every time and can be considered the extrinsic property. So instead of the bullet images being loaded off the hard disk everytime a round is fired, the images are loaded when the game loads. The problem is now reduced such that for every round fired, the same image is drawn on the screen multiple times.
In computing, minimising resource usage is of paramount importance. Flyweight pattern helps immensely by helping the programmer create resources only once and use them several times. If repetition has been a bane in your life and in your software, then you should give flyweight pattern a try.