A Flyweight Example In Python

Learn to utilize Flyweight design pattern to maintain code efficiency using an example.

Overview

We’ll start with some concrete classes for an IoT device that works with GPS messages. We don’t want to create a lot of individual Message objects with duplicate values taken from a source buffer; instead, we want Flyweight objects to help save memory. This leverages two important features:

  • The Flyweight objects reuse bytes in a single buffer. This avoids data duplication in a small computer.

  • The Flyweight classes can have unique processing for the various message types. In particular, the GPGGA, GPGLL, and GPRMC messages all have latitude and longitude information. Even though the details vary by message, we don’t want to create distinct Python objects. It’s a fair amount of overhead to handle the case when the only real processing distinction is the location of the relevant bytes within a buffer.

Here’s the UML diagram:

Press + to interact
The UML diagram of the GPS messages
The UML diagram of the GPS messages

Given a Buffer object with bytes read from the GPS, we can apply a MessageFactory to create Flyweight instances of the various Message subclasses. Each subclass has access to the shared Buffer object and can produce a Point object, but they have unique implementations reflecting the distinct structure of each message.

There’s an additional complication that is unique to Python. We can get into trouble when we have multiple references to an instance of the Buffer object. After working with a number of messages, we’ll have local, temporary data in each of the Message subclasses, including a reference to the Buffer instance.

The situation might look as shown in the following diagram, which has the concrete objects and their references:

Press + to interact
Reference diagram
Reference diagram

Some client application, shown as a Client object, has a reference to a Buffer instance. It read a bunch of GPS traffic into this buffer. Additionally, a specific GPGGA instance also has a reference to the Buffer object because offset 0 in the buffer had a GPGGA message. Offsets 68 and 98 have other messages; these will also have references back ...