Flyweight Pattern

The Flyweight Pattern is mainly used to reduce the number of objects created, in order to reduce memory usage and improve performance. It provides a way to reduce the number of objects needed for an application by attempting to reuse existing objects of the same type. If a matching object is not found, a new object is created. The flyweight pattern effectively supports the reuse of a large number of fine-grained objects through shared technology. The system only uses a small number of objects, which are very similar and have minimal state changes, thus enabling multiple reuse of objects. Because the flyweight pattern requires shareable objects to be fine-grained objects, it is also known as a lightweight pattern and is a type of object structural pattern.

Description

Object-oriented technology can effectively solve some flexibility or scalability issues, but in many cases, increasing the number of classes and objects in the system can lead to high running costs, resulting in performance degradation, and other issues. The flyweight pattern was born to solve this type of problem. It achieves the reuse of identical or similar objects through sharing technology. In the flyweight pattern, the same content that can be shared is called the intrinsic state, while the content that requires an external environment to be set and cannot be shared is called the extrinsic state. By distinguishing between the intrinsic state and the extrinsic state, the same object can have different features by setting different external states, while the same intrinsic state can be shared. In the flyweight pattern, the factory pattern usually appears, where a flyweight factory needs to be created to maintain a flyweight pool for storing flyweight objects with the same intrinsic state. In actual use, the shareable intrinsic state is limited, so flyweight objects are generally designed to be smaller, with fewer internal states. These objects are also known as fine-grained objects. The purpose of the flyweight pattern is to achieve the reuse of a large number of fine-grained objects using shared technology.

Pattern Structure

  • Flyweight: Abstract flyweight class.
  • ConcreteFlyweight: Concrete flyweight class.
  • UnsharedConcreteFlyweight: Non-shareable concrete flyweight class.
  • FlyweightFactory: Flyweight factory class.

Advantages

  • The flyweight pattern can greatly reduce the number of objects in memory, so that the same or similar objects are only stored once in memory.
  • The external state of the flyweight pattern is relatively independent and does not affect its internal state, allowing flyweight objects to be shared in different environments.

Disadvantages

  • The flyweight pattern makes the system more complex, requiring the separation of internal and external states, which complicates the logic of the program.
  • In order to share objects, the flyweight pattern needs to externalize the state of flyweight objects, which can lead to longer running times when reading the external state.

Applicable Scenarios

  • The system has a large number of identical or similar objects, leading to a large consumption of memory.

  • Most of the object's state can be externalized and passed into the object.

  • Using the flyweight pattern requires maintaining a flyweight pool for storing flyweight objects, which consumes resources, so it is worth using the flyweight pattern only when flyweight objects are reused multiple times.

Implementation

class Tea { // Tea product class, an instance is the object to be shared
    constructor(preference){
        this.preference = preference;
    }
}

class TeaMaker { // As a tea factory to create instances of tea, i.e., a flyweight factory responsible for maintaining a flyweight pool
    constructor(){
        this.availableTea = {};
    }

    make(preference) {
        this.availableTea[preference] = this.availableTea[preference] || (new Tea());
        return this.availableTea[preference];
    }
}

(function TeaShop(){
    const shop = new TeaMaker();
    var lessSugar1 = shop.make("less sugar");
    var moreMilk1 = shop.make("more milk");
    var withoutSugar1 = shop.make("without sugar");
    var lessSugar2 = shop.make("less sugar");
    var moreMilk2 = shop.make("more milk");
    var withoutSugar3 = shop.make("without sugar");
    console.log(lessSugar1 === lessSugar2); // true
    console.log(moreMilk1 === moreMilk2); // true
    console.log(withoutSugar1 === withoutSugar3); // true
})();

EveryDay Question

https://github.com/WindrunnerMax/EveryDay

References

https://www.runoob.com/design-pattern/flyweight-pattern.html https://github.com/sohamkamani/javascript-design-patterns-for-humans#-flyweight https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/flyweight.html