Flyweight Pattern

The Flyweight design pattern is used to minimize memory usage and improve performance by sharing common state between multiple objects.

It allows objects with similar or identical data to share resources rather than creating separate instances for each.

Think of it as using a single reusable template for creating objects with shared characteristics.

Flyweight Pattern C++ Example:

Let’s build a simple example of the Flyweight pattern to represent a text editor where multiple characters of the same font style can be represented by a shared flyweight object.

#include <iostream>
#include <string>
#include <unordered_map>

// Flyweight: Common interface for shared flyweight objects
class Font {
public:
    virtual void render(const std::string& text) const = 0;
    virtual ~Font() {}
};

// Concrete Flyweight: Shared flyweight object for a specific font style
class ConcreteFont : public Font {
public:
    ConcreteFont(const std::string& fontName) : fontName_(fontName) {}

    void render(const std::string& text) const override {
        std::cout << "Rendering text: '" << text << "' in font: " << fontName_ << std::endl;
    }

private:
    std::string fontName_;
};

// Flyweight Factory: Manages shared flyweight objects
class FontFactory {
public:
    Font* getFont(const std::string& fontName) {
        auto it = fonts_.find(fontName);
        if (it != fonts_.end()) {
            return it->second;
        } else {
            Font* font = new ConcreteFont(fontName);
            fonts_[fontName] = font;
            return font;
        }
    }

    ~FontFactory() {
        for (auto& entry : fonts_) {
            delete entry.second;
        }
    }

private:
    std::unordered_map<std::string, Font*> fonts_;
};

int main() {
    FontFactory fontFactory;

    // Client code: Use the font factory to get flyweight objects
    Font* font1 = fontFactory.getFont("Arial");
    Font* font2 = fontFactory.getFont("Times New Roman");

    // Both font1 and font2 are flyweight objects sharing the same font "Arial"
    font1->render("Hello");
    font2->render("World");

    // Clean up
    delete font1;
    delete font2;

    return 0;
}

Flyweight Pattern Explanation:


In this example, we have a Font interface that defines the common method render() for rendering text in different font styles.

The ConcreteFont class is a concrete flyweight that implements the Font interface. It represents a specific font style and can be shared among multiple text renderings with the same font.

The FontFactory class is a flyweight factory responsible for managing shared flyweight objects. It uses an unordered map (fonts_) to store and retrieve flyweight objects based on their font names. If a requested font already exists in the map, it returns the existing flyweight; otherwise, it creates a new one, adds it to the map, and returns it.

In the main() function, we demonstrate how the Flyweight pattern works. We use the FontFactory to get flyweight objects representing different font styles. Even if multiple renderings use the same font style (e.g., “Arial”), they share the same flyweight object, reducing memory usage.

Applications of the Flyweight Design Pattern:

  1. Text Editors: Sharing font and style information across multiple characters in a text.
  2. Graphical User Interfaces (GUI): Reusing common graphical elements (e.g., icons, buttons) in multiple parts of the interface.
  3. Game Development: Sharing assets, textures, or sprites for game objects with similar properties.

Pros of the Flyweight Design Pattern:

  • Memory Efficiency: Reduces memory usage by sharing common state among multiple objects.
  • Performance Improvement: Improves performance by reusing shared flyweight objects instead of creating new ones.
  • Flexibility: Allows adding new flyweight objects without affecting the existing ones.

Cons of the Flyweight Design Pattern:

  • Complexity: May add some complexity, especially when managing shared objects and their states.
  • Design Overhead: Requires identifying and separating intrinsic and extrinsic states in the flyweight objects.

In summary, the Flyweight pattern is useful when you have a large number of objects with shared characteristics and want to reduce memory usage and improve performance. It allows objects to share common state while still having separate unique states. However, it’s essential to use the pattern judiciously, as managing shared objects can add some complexity to the codebase.

Leave a Reply