Python Flyweight Design Pattern

1. Definition

The Flyweight Design Pattern is a structural pattern that aims to use shared objects to efficiently support large numbers of fine-grained objects.

2. Problem Statement

Suppose you're developing a system where thousands or millions of objects need to be created. Creating each object consumes memory, and when the number of objects becomes large, it can lead to significant memory overhead.

3. Solution

The solution is to use shared objects to avoid the overhead of creating and storing individual instances. The Flyweight pattern emphasizes the reuse of existing objects rather than the creation of new ones.

4. Real-World Use Cases

1. In graphics software, it can be used to prevent storing duplicate patterns or textures in memory.

2. In gaming, when representing large numbers of characters or items without consuming excessive resources.

3. Text formatting where different styles and fonts are applied, but intrinsic data (like characters) remain unchanged.

5. Implementation Steps

1. Divide the target class's properties into intrinsic (shared) and extrinsic (external) states.

2. Remove the extrinsic states from the class attributes and move them to the method parameters.

3. Define a factory that manages and creates instances of the flyweight objects and ensures sharing.

6. Implementation in Python

# Flyweight class
class TreeType:
    def __init__(self, name, color):
        self._name = name
        self._color = color
    def display(self, x, y, age):
        return f"Tree of type: {self._name}, color: {self._color}, positioned at ({x}, {y}), age: {age} years"
# Flyweight factory
class TreeFactory:
    _tree_types = {}
    @staticmethod
    def get_tree_type(name, color):
        key = (name, color)
        tree_type = TreeFactory._tree_types.get(key)
        if not tree_type:
            tree_type = TreeType(name, color)
            TreeFactory._tree_types[key] = tree_type
        return tree_type
# Client code
tree1 = TreeFactory.get_tree_type("Pine", "Green")
tree2 = TreeFactory.get_tree_type("Maple", "Red")
tree3 = TreeFactory.get_tree_type("Pine", "Green")
output1 = tree1.display(10, 20, 5)
output2 = tree2.display(30, 40, 6)
output3 = tree3.display(50, 60, 7)

Output:

"Tree of type: Pine, color: Green, positioned at (10, 20), age: 5 years"
"Tree of type: Maple, color: Red, positioned at (30, 40), age: 6 years"
"Tree of type: Pine, color: Green, positioned at (50, 60), age: 7 years"

Explanation:

1. The TreeType class represents our Flyweight. It holds the intrinsic state (name and color).

2. The extrinsic state (x, y coordinates, and age) is passed into the display method and is not stored within the flyweight objects.

3. The TreeFactory class is responsible for creating and managing flyweight objects, ensuring that objects with the same intrinsic state are shared and not duplicated.

4. The client code uses the TreeFactory to retrieve instances of TreeType. It reuses the Pine tree type, demonstrating that the same object is used for tree1 and tree3.

7. When to use?

The Flyweight Pattern is useful when:

1. An application uses a large number of objects, which results in a significant memory footprint.

2. Object states can be externalized, and most of the object data can be shared.

3. The application doesn't rely on object identity, and shared flyweight objects will not affect the application's behavior.


Comments