C++ Flyweight Design Pattern Example

1. Definition

The Flyweight Design Pattern uses sharing to support large numbers of similar objects efficiently, by reusing the common parts and minimizing memory usage.

2. Problem Statement

Imagine creating thousands or millions of similar objects where only a small amount of data changes between instances. Instantiating such a large number of objects can be resource-intensive and inefficient, especially if most of the data they hold is redundant.

3. Solution

Instead of creating large numbers of similar objects, create a smaller number of unique "flyweight" objects that can be shared among the contexts that need them. Any unique, contextual data can be passed into the flyweight as it's used.

4. Real-World Use Cases

1. Representing text in a word processor, where each character might be a flyweight object.

2. Game development, where you might have thousands of trees or buildings with shared geometries but different positions.

5. Implementation Steps

1. Identify the common state (intrinsic) and unique state (extrinsic).

2. Create a flyweight class that represents the intrinsic state.

3. Maintain a flyweight factory that reuses existing flyweight objects or creates new ones if needed.

4. Ensure that the client code uses the flyweight factory and passes the extrinsic state to the flyweight when needed.

6. Implementation in C++

// Step 1: Identify intrinsic and extrinsic states
// In this example, 'Color' is intrinsic and 'Position' is extrinsic.
// Step 2: Create the Flyweight class
class Tree {
private:
    std::string color;
public:
    Tree(const std::string &color) : color(color) {}
    void display(const std::string &position) const {
        std::cout << "Tree of color " << color << " at position " << position << "\n";
    }
};
// Step 3: Flyweight Factory
class TreeFactory {
private:
    std::map<std::string, Tree*> trees;
public:
    ~TreeFactory() {
        for (auto &pair : trees) {
            delete pair.second;
        }
    }
    Tree* getTree(const std::string &color) {
        if (trees.find(color) == trees.end()) {
            trees[color] = new Tree(color);
        }
        return trees[color];
    }
};
int main() {
    TreeFactory factory;
    Tree* tree1 = factory.getTree("Green");
    tree1->display("10,20");
    Tree* tree2 = factory.getTree("Brown");
    tree2->display("15,25");
    Tree* tree3 = factory.getTree("Green");
    tree3->display("20,30");
    return 0;
}

Output:

Tree of color Green at position 10,20
Tree of color Brown at position 15,25
Tree of color Green at position 20,30

Explanation:

1. The Tree class represents the intrinsic state (color).

2. The TreeFactory reuses existing Tree objects if a tree of that color already exists; otherwise, it creates a new one.

3. In the main function, despite requesting a green tree twice, only one green tree object is created, demonstrating the pattern's efficiency.

7. When to use?

Use the Flyweight pattern when:

1. An application uses a large number of objects which consume a significant amount of memory due to shared states.

2. The object's state can be externalized and passed in when necessary.

3. The application does not depend on object identity.


Comments