This article is created in continuation of easy patterns series description and presents a structural pattern named a Flyweight which solves the problem of sharing complex objects with a similar logic to keep a performance and a memory usage to be optimized.

Please refer to the other pattern articles as well:

Creational patterns:

Structural patterns:

Behavioral patterns:

The main essence

A flyweight — it is a shared object that can be used in multiple contexts simultaneously. For example each table renderer has several object kinds, like rows and cell. Lets imagine a picture when you have a table with two rows and two columns inside. Each instance has own class: for rows it would be the Row class and for cell it would be the Cell class. In such configuration you have to instantiate six objects (2x Row class and 4x Cell class) to describe such table content. Looks like a plan, right?

Lets pretend your table content dramatically increased with time and now you have a table with 500 rows and 8 columns. So, lets make some calculations:

const rowNumber = 500;

const columnNumber = 8; const getRowClassNumber = rowNumber => rowNumber;

const getCellClassNumber = (rowNumber, columnNumber) => rowNumber * columnNumber; getRowClassNumber(rowNumber); // 500

getCellClassNumber(rowNumber, columnNumber); // 500 * 8 // Result

// 500 + 500 * 8 === 4500!!!

That’s the result. Basically with a such approach we need to use 4500 class instances to describe each row and cell of such table…

But lets assume we understand that at one point of time the user can see only 10 rows of a content. So, actually we can reuse instances only for visible area. In such case the number of instances we need:

const rowNumber = 10;

const columnNumber = 8; const getRowClassNumber = rowNumber => rowNumber;

const getCellClassNumber = (rowNumber, columnNumber) => rowNumber * columnNumber; getRowClassNumber(rowNumber); // 10

getCellClassNumber(rowNumber, columnNumber); // 10 * 8 // Result

// 10 + 10 * 8 === 90

Basically we’re reducing memory consumption for 50 times.

How can we make such shareable class instances? The answer is to make them a flyweights. Flyweights cannot make assumptions about the context in which they operate. The main concept is to split their internal state to intristic and extrinsic. Intrinsic state consists of information that’s independent of the flyweight’s context (shares it). Extrinsic state depends on the flyweight’s context.

This patterns includes three main roles:

Client — maintains a reference to flyweight

— maintains a reference to flyweight FlyweightFactory —creates and manages flyweights

—creates and manages flyweights Flyweight — implements the Flyweight interface and add intrinsic state inside

Example of use

Let’s create a table with content. Once it’s scrolled by 1 position we wouldn’t create new row and cell instances, but will update existing ones with a new content. And so on… In current example I don’t use huge mock of data to render, but just generate new content on the fly. Intrinsic state keeps render methods, links to DOM etc. Extrinsic state keeps the information about current cell content which is to be updated right after scroll position is changed.