Skip to content

Flyweight Pattern

Pablo Garcia edited this page Jul 22, 2017 · 11 revisions

The Flyweight pattern is a classical structural solution for optimizing code that is repetitive, slow and inefficiently shares data. It aims to minimize the use of memory in an application by sharing as much data as possible with related objects (e.g application configuration, state and so on).

- Learning JavaScript Design Patterns

How to use

Instance Properties

flyweights (type: Object) Key-value pair list with the objects added.

Instance Methods

create(name, creator, ...args) Creates new instances based on a heuristic.

  • name (type: String) Alias of the new object to be created.
  • creator (type: Object or Function) Value of the new object, if it is a function it will be executed with the arguments passed.
  • args (type: Anything) Arguments that only matter if the `creator is a function. These will be passed as arguments.

heuristic(name) Returns true to create a new instance.

  • name (type: String) Alias of the new object to be created.

Examples

Basic Use Case

The most basic implementation, of all the patterns, do not require any options.

var patterns = require('go-patterns');

var Flyweight = patterns.flyweight().build();
var flyweight = new Flyweight();
var someObject = flyweight.create('someObject', { test: 'testing' });
var sameObject = flyweight.create('someObject', { test: 'should not overwrite previous object' });

console.log(flyweight.flyweights['someObject'].test); // => testing
console.log(flyweight.flyweights['someObject'] === someObject); // => true
console.log(flyweight.flyweights['someObject'] === sameObject); // => true

Verbose Use Case

This little example shows memoization with a factorial algorithm using flyweight.

var patterns = require('go-patterns');

var FactorialMemoizationFlyweight = patterns.flyweight({
  constructor: function() {
    // shadowing
    this.create = this.create.bind(this);
  },
  publics: {
    create(val) {
      return this.flyweights[`${val}`] = this.flyweights[`${val}`] || this.factorial(val);
    },
    factorial(val) {
      if(val <= 1) return 1;
      return val * this.factorial(val - 1);
    }
  }
}).build();

factorialMemoizationFlyweight = new FactorialMemoizationFlyweight();

[2, 3, 4, 4].forEach(factorialMemoizationFlyweight.create);

console.log(factorialMemoizationFlyweight.flyweights); // => { '2': 2, '3': 6, '4': 24 }

Advanced Use Case: Heavy Object Initialization.

var patterns = require('go-patterns');

function HeavyObjectInitialization(value) {
  this.data = value;
  this.store = [];
  for(var i = 0; i < value; i++) {
    this.store.push((i + 1) * Math.random());
  }
}

var LightObjectCreation = patterns.flyweight({
  constructor: function() {
    // this overrides the default object.
    this.flyweights = [];
  },
  publics: {
    heuristic(params) {
      return this.find(params) || this.construct(params);
    },
    construct(params) {
      var heavyObject = new HeavyObjectInitialization(params.data);
      this.flyweights.push(heavyObject);
      return heavyObject;
    },
    find(params) {
      for(var i = 0, l = this.flyweights.length; i < l; i++) {
        if(this.flyweights[i].data === params.data) {
          return this.flyweights[i];
        }
      }
      return null;
    }
  }
}).build();

var lightObjectCreation = new LightObjectCreation();

lightObjectCreation.create({
  data: 2 // dummy specific data
});
lightObjectCreation.create({
  data: 2 // dummy specific data
});

console.log(lightObjectCreation.flyweights); // => [ HeavyObjectInitialization { data: 2, store: [ 0.39935513992626603, 1.7727831649111456 ] } ]