Design Pattern: Flyweight Pattern in TypeScript

Flyweight pattern uses shared object to save resources and optimize memory use.

This article demonstrates Flyweight pattern implementations in TypeScript. Check the implementation detail and examples.

Implementation

Here is how to implement the Flyweight pattern-

  • We need an “Item” class. Purpose of this pattern implementation is to generate lots of item objects, using less resources.
  • We need a factory class. factory class holds a list of objects generated, which are divided by some type/category/block. 
  • Details of the object is added later, when we use the object.
  • There is a static method in the factory, which checks if an object exists of the same type in the list. If there is an existing object, then that is returned, else a new object of the type/category is created and returned.

Here is a simple example:

// Flyweight pattern implementation

// Item class
class Item {
    private prop: string = '';

    setProp(param1: string) {
        this.prop = param1;
    }

    print() {
        console.log("Prop: " + this.prop);
    }
}

// Item factory
class ItemFactory {
    static items: Map<string, Item> = new Map<string, Item>();

    static getItem(type: string): Item {
        let item = this.items.get(type);

        if (null != item) {
            return item;
        }

        item = new Item();
        this.items.set(type, item);

        return item;
    }
}


// Demo
// lets generate and print 10,000 objects of different type
const types = ['TYPE_A', 'TYPE_B'];

for (let i = 0; i < 10000; i++) {
    for (let type of types) {
        const item = ItemFactory.getItem(type);

        item.setProp("val_" + Math.random()); // For demo purpose

        item.print();
    }
}

console.log("Total number of objects used: " + ItemFactory.items.size);

The output of the above code-

Prop: val_0.06805408842853145
Prop: val_0.8317093448479642
Prop: val_0.6269462583567764
Prop: val_0.348759434122468
Prop: val_0.9970946342039331
Prop: val_0.7511190652163693
Prop: val_0.7025463044751803
Prop: val_0.6917019796094173
Prop: val_0.5929520824043306
Prop: val_0.9384624766677538
Prop: val_0.5879663161183588
Prop: val_0.2329742150030223
Prop: val_0.24014861153216938
Prop: val_0.5155366087063125
Prop: val_0.5033003382127474
Prop: val_0.35241143083451076
Prop: val_0.4885487146639411
Prop: val_0.06628825881934186
Prop: val_0.6752506202115875

.
.
.
.
.
.

// -- more output here
.
.
.
.

Total number of objects used: 2

You can see the total number of objects used here is 2(two), though we have operated on thousands of items.

Examples

Here are a few examples of Flywieght pattern implementation in TypeScript.

Example #1: Table Cells

In this example, we want to print thousands of table cells. If we do it in a general process, then thousands of cell objects will be created and stored in memory.

Using flyweight pattern, we can assign an object for each column. And add details (like content, width, etc.) while using the object.

That way only a few objects will be stored in memory. Let’s check step by step.

TableCell Class [Item Class]

  • Create file “table-cell.ts”.
  • Create class “TableCell”.
  • Define private property – “width” (width of the cell), “text” (content of the cell).
  • Width is fixed for all cells in the column, we are setting the width in the constructor.
  • The text prop has a set method. This prop will be different for each cell, that’s why we will set the value while using that specific cell.
// table-cell.ts

class TableCell {
    private width: number;
    private text: string = '';

    constructor(width: number) {
        this.width = width;
    }

    setText(text: string) {
        this.text = text;
    }

    draw() {
        console.log("Drawing cell : width = " + this.width + " | text = " + this.text);
    }
}

export default TableCell;

TableCellFactory Class

  • Create file “table-cell-factory.ts”.
  • Create class “TableCellFactory”.
  • Define a static property to store a list of “TableCell”.
  • Define static method “getTableCell”. In the method, if an object exists for a column then return it, else create a new “TableCell” object and return it.
// table-cell-factory.ts

import TableCell from "./table-cell";

class TableCellFactory {
    static tableCells = new Map<number, TableCell>();

    static getTableCell(column: number, width: number): TableCell {
        let tableCell = this.tableCells.get(column);

        if (null != tableCell) return tableCell;

        tableCell = new TableCell(width);
        this.tableCells.set(column, tableCell);

        return tableCell;
    }

    // For demo purpose only, not required in actual implementation
    static getCellObjectCount(): number {
        return this.tableCells.size;
    }
}

export default TableCellFactory;

Demo

For using the implementation, we can pass the column to the static method “getTableCell”, which will generate and return “TableCell” for a column.

Later we can set the text while printing.

// demo.ts

import TableCellFactory from "./table-cell-factory";

// For demo there are 5 columns with width 3, 6, 2, 5, 10 of some standard unit
const columnWidths: number[] = [3, 6, 2, 5, 10];

// Print 1000 rows
for (let row = 0; row < 1000; row++) {
    for (let column = 0; column < columnWidths.length; column++) {
        const tableCell = TableCellFactory.getTableCell(column, columnWidths[column]);
        tableCell.setText(row + "-" + column); // For demo purpose, text can come from any other sources

        tableCell.draw();
    }
}

console.log("Total number of tree objects: " + TableCellFactory.getCellObjectCount());

Output

Though we have operated on thousands of “TableCell” objects, but we will find that only 5 objects were actually generated.

Output of the code will be as below-

Drawing cell : width = 3 | text = 0-0
Drawing cell : width = 6 | text = 0-1
Drawing cell : width = 2 | text = 0-2
Drawing cell : width = 5 | text = 0-3
Drawing cell : width = 10 | text = 0-4
Drawing cell : width = 3 | text = 1-0
Drawing cell : width = 6 | text = 1-1
Drawing cell : width = 2 | text = 1-2
Drawing cell : width = 5 | text = 1-3
Drawing cell : width = 10 | text = 1-4
Drawing cell : width = 3 | text = 2-0
Drawing cell : width = 6 | text = 2-1
Drawing cell : width = 2 | text = 2-2
Drawing cell : width = 5 | text = 2-3
Drawing cell : width = 10 | text = 2-4
Drawing cell : width = 3 | text = 3-0
Drawing cell : width = 6 | text = 3-1
Drawing cell : width = 2 | text = 3-2
Drawing cell : width = 5 | text = 3-3
Drawing cell : width = 10 | text = 3-4
Drawing cell : width = 3 | text = 4-0
Drawing cell : width = 6 | text = 4-1
Drawing cell : width = 2 | text = 4-2
Drawing cell : width = 5 | text = 4-3
Drawing cell : width = 10 | text = 4-4
Drawing cell : width = 3 | text = 5-0
Drawing cell : width = 6 | text = 5-1
Drawing cell : width = 2 | text = 5-2
Drawing cell : width = 5 | text = 5-3
Drawing cell : width = 10 | text = 5-4
Drawing cell : width = 3 | text = 6-0
Drawing cell : width = 6 | text = 6-1
Drawing cell : width = 2 | text = 6-2
Drawing cell : width = 5 | text = 6-3
Drawing cell : width = 10 | text = 6-4
Drawing cell : width = 3 | text = 7-0
Drawing cell : width = 6 | text = 7-1
Drawing cell : width = 2 | text = 7-2
Drawing cell : width = 5 | text = 7-3
Drawing cell : width = 10 | text = 7-4
Drawing cell : width = 3 | text = 8-0
Drawing cell : width = 6 | text = 8-1
Drawing cell : width = 2 | text = 8-2
Drawing cell : width = 5 | text = 8-3
Drawing cell : width = 10 | text = 8-4
Drawing cell : width = 3 | text = 9-0
Drawing cell : width = 6 | text = 9-1
Drawing cell : width = 2 | text = 9-2
Drawing cell : width = 5 | text = 9-3
Drawing cell : width = 10 | text = 9-4
Drawing cell : width = 3 | text = 10-0
Drawing cell : width = 6 | text = 10-1
Drawing cell : width = 2 | text = 10-2
Drawing cell : width = 5 | text = 10-3
Drawing cell : width = 10 | text = 10-4
Drawing cell : width = 3 | text = 11-0
Drawing cell : width = 6 | text = 11-1
Drawing cell : width = 2 | text = 11-2
Drawing cell : width = 5 | text = 11-3
Drawing cell : width = 10 | text = 11-4
.
.
.
...// more output lines like this
.
.
.
.
Total number of tree objects: 5

Source Code

Use the following link to get the source code:

Other Code Implementations

Use the following links to check Flyweight pattern implementation in other programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.