Design Patterns in Ruby – Structural Patterns – Flyweight Pattern

Tram Ho

Hi everyone, so I went through most of the common Structural Patterns and the following will be an article about a recent model that is no longer popular because people are getting richer and upgrading RAM is very simple. @ Flyweight Pattern!

Intent (general)

** Flyweight ** is a structure design that allows you to save more objects into the amount of RAM available by sharing common state parts between multiple objects instead of keeping all the data in each object.

Problem

To have a fun after long hours of work, you decide to create a simple video game: players will move around the map and shoot each other. You have chosen to implement an actual particle system and make it a special feature of the game. A large number of bullets, rockets and shrapnel from the explosion will fly around the map and bring thrilling experience for players.

Once completed, push the commit, build the game, and send it to your friend to try it out. Although the game has run perfectly on your computer, your friend could not play for long. On my computer, the game keeps crashing after a few minutes of playing the game. After spending a few hours digging through the debug logs, you discover that the game has crashed due to insufficient RAM.

Practical problems related to your particle system. Each particle, such as a bullet, a rocket or a piece of ammunition is represented by a separate object that contains a lot of data. At some point, when the slaughter on the player screen reached its climax, the newly created particles no longer matched the remaining RAM, so the program crashed.

Solution

On closer inspection of the Particle class, you may notice that the color and sprite fields consume a lot more memory than other fields. What’s worse is that these two fields store almost identical data across all particles. For example, all bullets have the same color and sprite.

Upon closer inspection of the Particle class, you may notice that the color and sprite fields use more memory than the other fields. What’s worse is that these two fields store almost identical data on all particles. For example, all bullets have the same color and sprite.

The states of other particles, such as coordinates, movement vector and speed, are unique to each particle. The values ​​of these fields change the context. while color and sprite unchanged.

The constant data of an object is often called the intrinsic state . Other objects can only read it, cannot change it. The rest of the object state, often altered by other objects, is called extrinsic state .

The Flyweight pattern suggests that you stop storing extrinsic state inside the object. Instead, you should convert these states to specific methods based on it. Only the intrinsic state is in the object, allowing you to reuse it in different contexts.

Back to our game. Assuming that we extracted the outer state from our particle layer, there are only three different objects enough to represent all the particles in the game: a bullet, a rocket and a shard. As you can guess now, an object that only stores internal state is called flyweight.

Extrinsic state storage

Where does the outside move to? Some classes should still store it, right? In most cases, it is moved to the container object, it aggregates the objects before we apply the template.

In our case, it’s the main Game object that stores all the particles in the particles field. To move an external state into this class, you need to create several array fields to store the coordinates, vectors, and speed of each particle individually. But that is not all. You need another array to store references to a specific flyweight that represents a county. These arrays must be synchronized so that you can access all the data for a particle using the same index.

A better solution is to create a separate context class that will store the external state along with a reference to the flyweight object. This approach will require only a single array in the container class.

Oh wait !! Do we need to have as many contextual objects as we initially have? Technically, yes. But the important thing is, the objects are much smaller than before. The most memory-intensive fields have been moved to only a few flyweight objects. Now, a thousand small contextual objects can reuse the heaviest flyweight object instead of storing a thousand copies of its data.

Flyweight and immutability

Because the same flyweight object can be used in different contexts, you must make sure that its state cannot be modified. A flyweight should initialize its state only once, via the constructor parameters.

Flyweight factory

For more convenient access to the different flyweight, you can create a factory method that manages an existing group of flyweight objects. The method of getting the intrinsic state of the desired flyweight from the client as a parameter, searching for an existing flyweight object that matches this state and returning it if found. If not, it creates a new flyweight object and adds it to memory reuse.

Structure (organization)

  1. The Flyweight pattern is merely an optimization. Before applying it, make sure your program has RAM consumption issues related to having a large number of similar objects in memory at the same time. Make sure this problem cannot be resolved in any other way.
  2. The Flyweight class contains an initial state of an object that can be shared among multiple objects. The same flyweight object can be used in many different contexts. The state stored inside a flyweight is called an “intrinsic”. The state passed to the flyweight method is called “extrinsic”.
  3. The Context class contains an extrinsic state. When a context is paired with one of the flyweight objects, it represents the full state of the original object.
  4. Typically, the behavior of the original object is still in the Flyweight class; in this case, whenever calling a flyweight method, it must pass the appropriate extrinsic state values ​​to the method’s parameters. On the other hand, the behavior can be passed to the Context class, which will use the associated flyweight as a data object only.
  5. The client calculates or stores the extrinsic state of the flyweights. From a client’s perspective, flyweight is a sample object that can be configured at run time by passing some contextual data into the parameters of its methods.
  6. Flyweight Factory manages a group of existing flyweight. The client will not create flyweights directly. Instead, they call the factory, passing it the intrinsic state of the desired flyweight. The factory looks at the previously created flyweight and returns an existing one that matches the search criteria or creates a new one if nothing is found.

Applicability (use when)

Use the Flyweight pattern only when your program must support a large number of objects that barely fit into the available RAM.

How to Implement (how to install)

  1. Dividing the fields of a class into a flyweight into two parts:
    • intrinsic state: fields that contain immutable and duplicate data on multiple objects
    • extrinsic state: fields that contain unique contextual data for each object
  2. Leaving the fields representing the intrinsic state in the class, make sure they are unchanged and only have their original values ​​from the constructor.
  3. Eliminate extrinsic state fields. Replace them with methods that represent the values ​​of extrinsic state fields.
  4. This is optional, create a factory class to manage the flyweights group. It should check an existing factory before creating a new one. Once the factory is up and running, customers only have to request the flyweight through it. They should describe the desired flyweight by moving its intrinsic state to the factory.
  5. The client must store or calculate values ​​of extrinsic state (context) in order to call methods of flyweight objects. For convenience, the extrinsic state along with the field referencing the flyweight can be converted to a separate context class.

Decorator in Ruby (example with ruby ​​language)

main.rb: Conceptual Example

output.txt: Execution result

Refer

refactoring.guru

Share the news now

Source : Viblo