Flyweight Pattern

Last Updated on September 24, 2023 by KnownSense

The Flyweight pattern is primarily employed to minimize the volume of object instances and, consequently, reduce memory consumption while enhancing performance. This design pattern falls within the structural pattern category, as it offers techniques for reducing the total number of objects, thereby enhancing the organization of objects within an application.

The Flyweight pattern aims to recycle similar objects by storing them and generating new instances only when no matching object is available.

In vector graphics, complex images are created using a combination of basic shapes, such as lines, circles, and polygons. These basic shapes can be reused multiple times within the same design.

Graphic design software, like Adobe Illustrator or CorelDRAW, often utilizes the Flyweight pattern to optimize memory usage when handling vector graphics.

Benefits

  1. Memory Efficiency: One of the primary advantages of the Flyweight pattern is its ability to significantly reduce memory consumption. By sharing common, intrinsic (invariant) properties among multiple objects, it minimizes the memory footprint, which is particularly valuable when dealing with a large number of similar objects.
  2. Improved Performance: Because the Flyweight pattern reduces the number of object instances and the memory overhead associated with them, it often leads to improved application performance. Fewer objects mean less memory allocation and deallocation overhead, resulting in faster execution.
  3. Scalability: When dealing with systems that need to handle a large number of objects, the Flyweight pattern can enhance scalability. It allows the system to maintain a reasonable memory footprint even as the number of objects grows, making it suitable for applications with varying workloads.
  4. Resource Conservation: By reusing shared flyweight objects, the pattern conserves system resources, such as CPU time and memory, which can be critical in resource-constrained environments or when optimizing applications for performance.
  5. Simplified Maintenance: The Flyweight pattern promotes code modularity and separation of concerns. It isolates the intrinsic state (shared properties) from the extrinsic state (context-dependent properties), making it easier to maintain and extend the codebase.
  6. Flexibility: This pattern provides flexibility by allowing you to dynamically create and share objects based on certain criteria. It’s particularly useful when you have a mix of shared and unique properties within your objects.
  7. Enhanced Object Structure: By reducing the number of object instances, the Flyweight pattern often results in a more organized and streamlined object structure, improving the overall design of the application.
  8. Consistent State: Flyweight objects are typically immutable or have their intrinsic state isolated, ensuring that shared properties remain consistent across the application.
  9. Reduced Initialization Overhead: Flyweight objects are often created and initialized once, and then reused, reducing the initialization overhead associated with creating new objects from scratch.
  10. Support for Large Data Sets: In scenarios where applications need to process or manage large data sets, such as databases or graphical representations, the Flyweight pattern can efficiently handle the storage and manipulation of shared data.
  11. Enhanced Performance in Multithreaded Environments: When properly implemented, the Flyweight pattern can facilitate safe and efficient multithreaded access to shared objects, as it reduces contention for resources.

UML of Flyweight pattern

Flyweight Pattern

Implementation

Let’s code to create a application that creates different shapes using flyweights pattern.

Step1: Create a interface for flyweight object

interface Shape {
    void draw(int x, int y);
}

Step2: Create concrete flyweight class for circle and line

class Circle implements Shape {
    private int radius;
    private Color color;

    public Circle(int radius, Color color) {
        this.radius = radius;
        this.color = color;
    }

    @Override
    public void draw(int x, int y) {
        System.out.println("Drawing a circle with radius " + radius + " at (" + x + ", " + y + ") in color " + color);
    }
}
class Line implements Shape {
    private int length;
    private Color color;

    public Line(int length, Color color) {
        this.length = length;
        this.color = color;
    }

    @Override
    public void draw(int x, int y) {
        System.out.println("Drawing a line with length " + length + " at (" + x + ", " + y + ") in color " + color);
    }
}

Step3: Create a ShapeFactory class to manage and create flyweight objects.

class ShapeFactory {
    private static final Map<String, Shape> shapes = new HashMap<>();

    public static Shape getShape(String key, int size, Color color) {
        String shapeKey = key + size + color.toString();

        if (!shapes.containsKey(shapeKey)) {
            if ("Circle".equalsIgnoreCase(key)) {
                shapes.put(shapeKey, new Circle(size, color));
            } else if ("Line".equalsIgnoreCase(key)) {
                shapes.put(shapeKey, new Line(size, color));
            }
        }

        return shapes.get(shapeKey);
    }
}

Step4: In main class use ShapeFactory to draw shapes with different coordinates and colors while reusing objects with the same characteristics to save memory.


public class FlyweightPatternExample {
    public static void main(String[] args) {
        // Client code
        Shape circle1 = ShapeFactory.getShape("Circle", 5, Color.RED);
        Shape circle2 = ShapeFactory.getShape("Circle", 5, Color.RED);
        Shape line1 = ShapeFactory.getShape("Line", 10, Color.BLUE);
        Shape line2 = ShapeFactory.getShape("Line", 10, Color.BLUE);

        circle1.draw(1, 1);
        circle2.draw(2, 2);
        line1.draw(3, 3);
        line2.draw(4, 4);

        // Both circle1 and circle2 refer to the same circle object in memory
        // Both line1 and line2 refer to the same line object in memory
        // The Flyweight pattern optimizes memory usage by sharing common objects.
    }
}

OUTPUT:
Drawing a circle with radius 5 at (1, 1) in color java.awt.Color[r=255,g=0,b=0]
Drawing a circle with radius 5 at (2, 2) in color java.awt.Color[r=255,g=0,b=0]
Drawing a line with length 10 at (3, 3) in color java.awt.Color[r=0,g=0,b=255]
Drawing a line with length 10 at (4, 4) in color java.awt.Color[r=0,g=0,b=255]

This output demonstrates the creation and drawing of circles and lines at different coordinates and with different colors. Notice that the Flyweight pattern ensures that identical shapes with the same size and color are reused, optimizing memory usage.

Conclusion

In conclusion, the Flyweight pattern is a structural design pattern that optimizes memory usage by sharing and reusing common, immutable objects across multiple contexts. It’s particularly useful when dealing with a large number of similar objects, such as in graphics or text processing, where it reduces memory overhead and improves performance by minimizing object duplication. By separating intrinsic and extrinsic state, the Flyweight pattern allows for efficient management of resources and is a valuable tool for achieving memory efficiency in software applications.

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to Top