DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for Javascript Design patterns: Flyweight Pattern
Jazsmith24
Jazsmith24

Posted on

Javascript Design patterns: Flyweight Pattern

The flyweight pattern is one of the structural design patterns. This pattern provides ways to decrease object count thus improving application required objects structure. It aims to minimize the use of memory in an application by sharing as much data as possible with related objects. One important feature of flyweight objects is that they are immutable. This means that they cannot be modified once they have been constructed.

Each "flyweight" object is divided into two pieces: the state-dependent (extrinsic) part, and the state-independent (intrinsic) part. The intrinsic state is stored (shared) in the Flyweight object. The extrinsic state is stored or computed by client objects and passed to the Flyweight when its operations are invoked.

Intrinsic information may be required by methods on our objects, which they absolutely cannot function without. Extrinsic information can be removed and stored externally.

How does the flyweight pattern store values?

In the Flyweight pattern, we use a HashTable that stores reference to the object which has already been created, every object is associated with a key. HashTables are data structures that store data in an array-like format, using key/value pairs, where the (hashed) key corresponds to the index in the array. HashTables offer the same key/value functionality and come native in JavaScript in the form of the map() object.

Now when a client wants to create an object, he simply has to pass a key associated with it. If the object has already been created we simply get the reference to that object else it creates a new object and then returns its reference to the client.

Example

The Flyweight uses sharing to support large numbers of objects efficiently. Modern web browsers use this technique to prevent loading the same images twice. When a browser loads a web page, it traverses through all images on that page. The browser loads all-new images from the Internet and places them on the internal cache. For already loaded images, a flyweight object is created, which has some unique data like position within the page, but everything else is referenced to the cached one.

Let's take a look at an example from Addy Osmani's "Learning JavaScript Design Patterns" book which is about implementing a system to manage all of the books in a library.

The vital meta-data for each book could be:

  • ID
  • Title
  • Author
  • Genre
  • Page count
  • Publisher ID
  • ISBN

We'll have the following properties to keep track of which member has checked out a particular book, the date they've checked it out on as well as the expected date of return:

  • checkoutDate
  • checkoutMember
  • dueReturnDate
  • availability

Before any optimization using the Flyweight pattern, each book would be represented as follows:

prior flyweight

 let Book = function(
  id,
  title,
  author,
  genre,
  pageCount,
  publisherID,
  ISBN,
  checkoutDate,
  checkoutMember,
  dueReturnDate,
  availability
) {
  this.id = id;
  this.title = title;
  this.author = author;
  this.genre = genre;
  this.pageCount = pageCount;
  this.publisherID = publisherID;
  this.ISBN = ISBN;
  this.checkoutDate = checkoutDate;
  this.checkoutMember = checkoutMember;
  this.dueReturnDate = dueReturnDate;
  this.availability = availability;
};

Book.prototype = {
  getTitle: function() {
    return this.title;
  },

  getAuthor: function() {
    return this.author;
  },

  getISBN: function() {
    return this.ISBN;
  },

  // For brevity, other getters are not shown
  updateCheckoutStatus: function(
    bookID,
    newStatus,
    checkoutDate,
    checkoutMember,
    newReturnDate
  ) {
    this.id = bookID;
    this.availability = newStatus;
    this.checkoutDate = checkoutDate;
    this.checkoutMember = checkoutMember;
    this.dueReturnDate = newReturnDate;
  },

  extendCheckoutPeriod: function(bookID, newReturnDate) {
    this.id = bookID;
    this.dueReturnDate = newReturnDate;
  },

  isPastDue: function(bookID) {
    var currentDate = new Date();
    return currentDate.getTime() > Date.parse(this.dueReturnDate);
  }
};

Using thousands of book objects may overwhelm the available memory, but we can optimize our system using the Flyweight pattern to improve this.

We can now separate our data into intrinsic and extrinsic states as follows: data relevant to the book object (title, author, etc.) is intrinsic while the checkout data (checkoutMember, dueReturnDate, etc.) is considered extrinsic.

Effectively this means that only one Book object is required for each combination of book properties. It's still a considerable quantity of objects, but significantly fewer than we had previously.

The following single instance of our book meta-data combinations will be shared among all of the copies of a book with a particular title.

post flyweight

// Flyweight optimized version
var Book = function(title, author, genre, pageCount, publisherID, ISBN) {
  this.title = title;
  this.author = author;
  this.genre = genre;
  this.pageCount = pageCount;
  this.publisherID = publisherID;
  this.ISBN = ISBN;
};

The extrinsic states have been removed. Everything to do with library check-outs will be moved to a manager, and as the object data is now segmented, a factory can be used for instantiation.

Essentially Flyweight is an 'object normalization technique' in which common properties are factored out into shared flyweight objects. (Note: the idea is similar to data model normalization, a process in which the modeler attempts to minimize redundancy).

What's an advantage and a disadvantage of the flyweight pattern?

Disadvantage: Flyweights may introduce run-time costs associated with transferring, finding, and/or computing extrinsic state, especially if it was formerly stored as an intrinsic state.

Advantages*:

  • Space savings, which increase as more flyweights are shared. * Saves a lot of Megabytes.
  • Facing memory constraints and get thousands of similar objects.

Sources

https://www.geeksforgeeks.org/flyweight-design-pattern/
https://anasshekhamis.com/2017/11/16/flyweight-design-pattern-in-javascript/
https://www.dofactory.com/javascript/design-patterns/flyweight#:~:text=Essentially%20Flyweight%20is%20an%20'object,out%20into%20shared%20flyweight%20objects.&text=An%20example%20of%20the%20Flyweight,are%20shared%20across%20the%20application.

Top comments (0)

50 CLI Tools You Can't Live Without

The top 50 must-have CLI tools, including some scripts to help you automate the installation and updating of these tools on various systems/distros.