Hengyuan Pattern of Structural Design Pattern [Design Pattern Series]

Series Article Directory

C++ skill series
Linux communication architecture series
C++ high-performance optimization programming series
Deep understanding of software architecture design series
Advanced C++ concurrent thread programming
design pattern series

Looking forward to your attention! ! !
insert image description here

现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。
Now everything is for the future of dream weaving wings, let the dream fly in reality.

1. Introduction to Hengyuan Mode

亨元模式?不知道为啥起这么奇怪的名字!!!

Simple understanding: A class has many members, creating this object consumes resources, and in actual scenarios, the object needs to be created and destroyed repeatedly. The memory consumed is even larger.

If you design an object pool at this time, certain objects are cached in it, and the software applies for it when it is in use, and recycles it when it is not in use. Objects can be reused, and objects are created and destroyed multiple times.

什么是享元模式?

When it comes to Flyweight mode, the first thing that comes to mind is pool technology. String constant pool, database connection pool, buffer pool, etc. are all applications of Flyweight mode, so Flyweight mode is an important implementation of pool technology.

For example, every time we create a string object, we need to create a new string object, the memory overhead will be very large, so if the string object "adam" is created for the first time, the same string will be created next time" "adam", just point its reference to "adam", so that the sharing of the "adam" string in memory is realized.

To give the simplest example, when playing chess online, one server connects multiple clients (players). If we create objects for each chess piece, there may be hundreds of objects generated in a game of chess. If it is a little bit, because of the limited memory space, it is difficult for a server to support it, so the Flyweight mode is used here to reduce the chess piece objects to a few instances.

⚠️ 意图:
Efficiently support a large number of fine-grained objects using sharing techniques.

⚠️ 主要解决:
When there are a large number of objects, it may cause memory overflow. We abstract the common parts. If there are the same business requests, we will directly return the existing objects in memory to avoid recreation. .

⚠️ 何时使用:
1. There are a large number of objects in the system. 2. These objects consume a lot of memory. 3. Most of the state of these objects can be externalized. 4. These objects can be divided into many groups according to the intrinsic state. When the extrinsic objects are removed from the objects, each group of objects can be replaced by an object. 5. The system does not depend on the identity of these objects, and these objects are indistinguishable.

⚠️ 如何解决:
Judging by the unique identification code, if it exists in the memory, return the object identified by the unique identification code.

insert image description here

Figure 1_1 Hengyuan pattern class diagram

Because fine-grained objects are required, it is inevitable that there will be a large number of objects with similar properties. At this time, we divide the information of these objects into two parts: internal state and external state.

The internal state refers to the information shared by the object, which is stored inside the flyweight object and will not change with the change of the environment; the external
state refers to a mark that the object can rely on, which is a non-shareable state that changes with the change of the environment.

2. Advantages and disadvantages of Hengyuan model

2.1 Advantages

Greatly reduces the creation of objects, reduces program memory usage, and improves efficiency

  • The advantage of the flyweight mode is that it can greatly reduce the number of objects in memory, so that only one copy of the same object or similar objects is saved in memory.
  • The external state of the flyweight pattern is relatively independent and will not affect its internal state, so that the flyweight object can be shared in different environments.

2.2 Disadvantages

Increased system complexity. It is necessary to separate the internal state and the external state, and the external state has solidification characteristics and should not change with the change of the internal state

  • 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 make the object shareable, the flyweight pattern needs to externalize the state of the flyweight object, and reading the external state makes the running time longer.

The Flyweight pattern can avoid the overhead of a large number of very similar classes. In programming, sometimes it is necessary to generate a large number of fine-grained class instances to represent data. If you can find that these instances are basically the same except for a few parameters, you can sometimes greatly reduce the number of classes that need to be instantiated. If you can move those parameters outside of the class instance and pass them in when the method is called, you can drastically reduce the number of individual instances through sharing.

That is to say, the state required for Flyweight execution in Flyweight mode is internal or external. The internal state is stored in the ConcreteFlyweight object, while the external object should be considered to be stored or calculated by the client object. When calling Flyweight When an object is manipulated, pass that state to it.

3. Usage scenarios of Hengyuan mode

  • There are a large number of similar objects in the system
  • Scenarios that require a buffer pool

Note:
Pay attention to the division of internal state and external state, otherwise it may cause thread safety issues;
these classes must be controlled by a factory class.

4. Realization of Hengyuan Mode

The Flyweight abstract class
is the superclass or interface of all concrete flyweight classes. Through this interface, Flyweight can accept and act on external states.

#ifndef FLYWEIGHT_FLYWEIGHT_H
#define FLYWEIGHT_FLYWEIGHT_H

#include <iostream>
#include <string>
#include <utility>

using namespace std;
class Flyweight {
    
    
public:
    explicit Flyweight(string extrinsic) {
    
    
        extrinsic_ = std::move(extrinsic);
    }

    virtual ~Flyweight() = default;
    //定义业务操作
    virtual void operate(int extrinsic) = 0;

    string getIntrinsic() const {
    
    
        return intrinsic_;
    }

    void setIntrinsic(string intrinsic) {
    
    
        intrinsic_ = std::move(intrinsic);
    }

public:
    string intrinsic_; //内部状态
protected:
    //要求享元角色必须接受外部状态
    string extrinsic_;//外部状态

};


#endif //FLYWEIGHT_FLYWEIGHT_H

The ConcreteFlyweight class
inherits the Flyweight superclass or implements the Flyweight interface, and adds storage space for its internal state.

#ifndef FLYWEIGHT_CONCRETEFLYWEIGHT_H
#define FLYWEIGHT_CONCRETEFLYWEIGHT_H

#include "Flyweight.h"

class ConcreteFlyweight : public Flyweight{
    
    
    //接受外部状态
public:
    explicit ConcreteFlyweight(string extrinsic) : Flyweight(std::move(extrinsic)) {
    
    }
    ~ ConcreteFlyweight() = default;
    //根据外部状态进行逻辑处理
    void operate(int extrinsic) override {
    
    
        cout << "具体Flyweight:" << extrinsic << endl;
    }
};


#endif //FLYWEIGHT_CONCRETEFLYWEIGHT_H

The UnsharedConcreteFlyweight class
refers to those Flyweight subclasses that do not need to be shared.

#ifndef FLYWEIGHT_UNSHAREDCONCRETEFLYWEIGHT_H
#define FLYWEIGHT_UNSHAREDCONCRETEFLYWEIGHT_H

#include "Flyweight.h"

class UnsharedConcreteFlyweight : public Flyweight{
    
    
public:
    explicit UnsharedConcreteFlyweight(string extrinsic) : Flyweight(std::move(extrinsic)) {
    
    }
    ~UnsharedConcreteFlyweight() = default;
    //根据外部状态进行逻辑处理
    void operate(int extrinsic) override {
    
    
        cout << "不共享的具体Flyweight:" << extrinsic << endl;
    }
};


#endif //FLYWEIGHT_UNSHAREDCONCRETEFLYWEIGHT_H

The FlyweightFactory class is
a Flyweight factory used to create and manage Flyweight objects, mainly to ensure that Flyweight is shared reasonably. When a user requests a Flyweight, the FlyweightFactory object provides a created instance or creates an instance.

#include "Flyweight.h"
#include "ConcreteFlyweight.h"
#include <map>
#include <memory>

using namespace std;

class FlyweightFactory {
    
    
public:
    FlyweightFactory() = default;
    ~FlyweightFactory() = default;

    //享元工厂
public:
     shared_ptr<Flyweight> GetFlyweight(string extrinsic) {
    
    
        cout << extrinsic << endl;
        shared_ptr<Flyweight> flyweightPtr = nullptr;
        auto a = pool_.find(extrinsic);
        if(pool_.find(extrinsic) != pool_.end()) {
    
        //池中有该对象
            flyweightPtr = pool_.at(extrinsic);
            cout << "已有 " << extrinsic << " 直接从池中取---->" << endl;
        } else {
    
    
            //根据外部状态创建享元对象
            flyweightPtr = make_shared<ConcreteFlyweight>(extrinsic);
            //放入池中
            pool_.emplace(extrinsic, flyweightPtr);
           cout << "创建 " << extrinsic  <<  " 并从池中取出---->" << endl;
        }

        return flyweightPtr;
    }

    //定义一个池容器
private:
     map<string, shared_ptr<Flyweight>> pool_;
};


#endif //FLYWEIGHT_FLYWEIGHTFACTORY_H

Client client

#include <iostream>
#include "Flyweight.h"
#include "FlyweightFactory.h"
#include "UnsharedConcreteFlyweight.h"

using namespace std;
int main() {
    
    
    int extrinsic = 22;

    FlyweightFactory factory;

    shared_ptr<Flyweight> flyweightX = factory.GetFlyweight("X");
    flyweightX->operate(++extrinsic);

    shared_ptr<Flyweight> flyweightY = factory.GetFlyweight("Y");
    flyweightY->operate(++extrinsic);

    shared_ptr<Flyweight> flyweightZ = factory.GetFlyweight("Z");
    flyweightZ->operate(++extrinsic);

    shared_ptr<Flyweight> flyweightReX = factory.GetFlyweight("X");
    flyweightReX->operate(++extrinsic);

    shared_ptr<UnsharedConcreteFlyweight> unsharedFlyweight = make_shared<UnsharedConcreteFlyweight>("X") ;
    unsharedFlyweight->operate(++extrinsic);

    return 0;
}

The result of the operation is as follows:
insert image description here

Figure 1_2 Running results

From this result, we can see that when X, Y, and Z are created for the first time, they are all created first and then taken out of the pool. When X is created for the second time, because the pool already exists, it is taken out of the pool directly. , this is Flyweight mode.

V. Summary

and other related patterns:

The client wants to refer to the flyweight object, which is created or obtained through the factory object. Every time the client references a flyweight object, it can refer to the desired flyweight object through the same factory object. Therefore, the enjoyment factory can be designed as a singleton mode, so that the client can only refer to one factory instance. Because all flyweight objects are uniformly managed by a factory object, there is no need to refer to multiple factory objects on the client side. Whether it is a simple flyweight pattern or a flyweight factory role in a composite flyweight pattern, it can be designed as a singleton pattern, which will not have any impact on the result.

Composite mode: Flyweight mode is usually combined with Composite mode to implement a logical hierarchical structure with a directed acyclic graph of shared leaf nodes. Composite flyweight mode is actually a combination of simple flyweight mode and composition mode. A simple enjoyment object can be regarded as a leaf object and can be shared, while a compound enjoyment object can be used as a branch object, so an aggregation management method can be added to the compound enjoyment role. In general, it is best to implement State and Strategy objects with Flyweight.

summary:

  1. Flyweight mode is a design pattern that considers system performance. By using Flyweight mode, memory space can be saved and system performance can be improved.
  2. The core of the Flyweight mode lies in the Flyweight factory class. The function of the Flyweight factory class is to provide a Flyweight pool for storing Flyweight objects. When users need objects, they first obtain them from the Flyweight pool. If it exists, create a new flyweight object and return it to the user, and save the newly added object in the flyweight pool.
  3. The Flyweight mode efficiently supports a large number of fine-grained objects in a shared manner. The key to sharing Flyweight objects is to distinguish between internal state and external state.
    (1) The internal state is stored inside the flyweight object and will not change with the environment, so the internal state can be shared.
    (2) The external state is a state that changes with the environment and cannot be shared. The external state of the flyweight object must be saved by the client, and after the flyweight object is created, it is passed into the flyweight object when it needs to be used. One external state is independent of another external state.

Guess you like

Origin blog.csdn.net/weixin_30197685/article/details/131886656