This week we’ll look at a design pattern designed to optimize system performance — the Share element pattern. Sharing means sharing, which means that one thing is shared by many people, and this is the ultimate purpose of this model. Yuan means unit, fly-scale individual. The core of this model is to use sharing technology to effectively support a large number of fine-grained objects.

define

The shared element pattern requires that the attributes of an object be divided into internal and external states (states here generally refer to attributes). The goal is to minimize the number of shared objects, as shown in the UML diagram below:

  • Flyweight is an abstract actor that specifies the methods that must be implemented for the concrete actor.
  • ConcreteFlyweight is a method that implements an abstract role definition for a concrete role.
  • The FlyweightFactory is the privilege factory that creates and manages the privilege roles, which are used to construct a pool container and provide methods to get objects from the pool.
  • Client is a Client role that maintains references to all the metadata objects and stores the corresponding external state.

Usage scenarios

I believe that with so many conceptual issues, we still do not understand what is the sharing mode, or what is the use of the sharing mode? Here is a simple example to illustrate.

There is a garment factory, which produces 50 styles of men’s and women’s clothing. In order to promote the sales, we need to find models to take photos. Normally, we may find 50 male and 50 female models, and each model wears a kind of clothing and takes a group of photos. Its code implementation is as follows:

// class Modal {constructor(name, gender, clothes) { this.name = name this.gender = gender this.clothes = clothes } takePhoto() { Console. log(' ${this.gender} model ${this.name} wearing ${this.clothes} took a photo ')}}Copy the code
For (let I = 0; i < 50; I ++) {let manModel = new Modal(' piece ${I} ', 'male ',' suit ${I} ') manmodel. takePhoto()} for (let I = 50; i < 100; I++) {let womanModel = new Modal (` ${I} li `, 'female' and ` clothing ${I} `) womanModel. TakePhoto ()}Copy the code

The running result is shown as follows:

While this requirement was fulfilled, 100 model objects must have been created. Imagine that if the number of clothes continues to grow indefinitely, the number of models will also continue to grow, and when the number of objects reaches a certain point, the program will inevitably crash.

At this point the flyweight pattern can help us to solve the problem, analysing, no matter how many kinds of clothes, we only need to men and women each photograph of a model to wear clothes also can realize the demand, realize the core of the flyweight pattern is divided into internal and external state, the following a few experience can be divided for our rapidly to internal external state:

  1. Internal state is stored inside an object
  2. Internal state can be shared by several objects
  3. The internal state is independent of the specific scenario and usually does not change
  4. The external state depends on and changes according to the specific scenario. The external state cannot be shared

Through the analysis of the above method, it can be concluded that for the model object, gender is its internal state, while clothing is its external state. Now we use the sharing element model to transform this example

Build the share object

Class Modal {constructor(id, gender) {this.gender = gender this.name = 'zhang ${gender}${id}'}}Copy the code

Build the Heyuan factory

Class ModalFactory {// static create(id, gender) { if (this[gender]) { return this[gender] } return this[gender] = new Modal(id, gender) } }Copy the code

Managing external state

Class TakeClothesManager {// addClothes static addClothes(id, gender, clothes) {const modal = ModalFactory. Create (id, gender, clothes) gender) this[id] = { clothes, Modal}} // Take a photo static takePhoto(id) {const obj = this[id] Console. log(' ${obj.modal.gender} Model ${obj.modal.name} wore ${obj.clothes} took a photo ')}}Copy the code

perform

for (let i = 0; i < 50; I++) {TakeClothesManager. AddClothes (I, 'male', ` clothing ${I} `) TakeClothesManager. TakePhoto (I)} for (let I = 50; i < 100; I++) {const {addClothes, takePhoto} = TakeClothesManager TakeClothesManager. AddClothes (I, 'female', ` clothing ${I} `) TakeClothesManager. TakePhoto (I)}Copy the code

The running result is shown as follows:

It can be seen from the running result that the same function can be completed only by creating two model objects of different genders, which is the advantage of the sharing mode.

conclusion

The flyweight pattern optimization is a kind of very good performance, but it will also bring some complexity problems, from the example above you can see, after using the flyweight pattern, we need to maintain one more factory respectively objects, and to like a manager, in the most unnecessary use the flyweight pattern of environment, the costs can be avoided.

The benefits of the share pattern depend largely on how and when it is used. In general, the share pattern can be used when:

  • Most of the state of an object can be changed to an external state
  • A large number of similar objects are used in a program
  • Because a large number of objects are used, there is a large memory overhead
  • Once you strip away the external state of an object, you can replace a large number of objects with relatively few shared objects