javadesign-patternsflyweight-pattern

How does the Flyweight pattern in Java work with respect to memory management?


I feel like I have an ok grasp on the design pattern, however I can't seem to get my head around one thing and it doesn't seem to be exactly explained in the resources I've looked at.
That question is, how is the data common, without the data being static, considering the objects are separate entities?

https://www.tutorialspoint.com/design_pattern/flyweight_pattern.htm

In this example, I cannot figure out where the optimisation is occurring, as it looks as if the objects are just being created each time as normal.

Circle circle = (Circle)ShapeFactory.getCircle(getRandomColor());
circle.setX(getRandomX());
circle.setY(getRandomY());
circle.setRadius(100);
circle.draw();

This code block seems like my best guess as the first line retrieves from the HashMap a circle with a certain colour, but this creates a new instance of a circle, with no lasting reference to the colour of the circle.
Therefore, unless I'm mistaken, there is no actual shared data, so I am unsure of how this provides benefits other than maybe during creation.


Solution

  • The ShapeFactory in your linked example will create one Circle per color:

    import java.util.HashMap;
    
    public class ShapeFactory {
       private static final HashMap<String, Shape> circleMap = new HashMap();
    
       public static Shape getCircle(String color) {
          Circle circle = (Circle)circleMap.get(color);
    
          if(circle == null) {
             circle = new Circle(color);
             circleMap.put(color, circle);
             System.out.println("Creating circle of color : " + color);
          }
          return circle;
       }
    }
    

    If no Circle with a specified color exists, it will create a new Circle object and store this instance in the circleMap hashmap. If a Circle with a specific color already exists, it will return the already existing instance from the circleMap.

    This is also explained in the text:

    ShapeFactory has a HashMap of Circle having key as color of the Circle object. Whenever a request comes to create a circle of particular color to ShapeFactory, it checks the circle object in its HashMap, if object of Circle found, that object is returned otherwise a new object is created, stored in hashmap for future use, and returned to client.

    This is also evident in the output shown in the tutorial:

    Creating circle of color : Black
    Circle: Draw() [Color : Black, x : 36, y :71, radius :100
    Creating circle of color : Green
    Circle: Draw() [Color : Green, x : 27, y :27, radius :100
    Creating circle of color : White
    Circle: Draw() [Color : White, x : 64, y :10, radius :100
    Creating circle of color : Red
    Circle: Draw() [Color : Red, x : 15, y :44, radius :100
    Circle: Draw() [Color : Green, x : 19, y :10, radius :100
    Circle: Draw() [Color : Green, x : 94, y :32, radius :100
    Circle: Draw() [Color : White, x : 69, y :98, radius :100
    

    Each colored Circle is only created once, but modified many times.


    I agree that the tutorial doesn't really show the benefit of a Flyweight though. The main point of the flyweight is to externalise shared state. The usual examples I know use character properties in a document.

    Instead of having one Character with position, font, size and textDecoration, you would externalize the latter three, thereby reducing the memory needed for each Character instance:

    This is some text.

    In the line above, the individual characters would only need to store their position, but the formatting is the same, so that can be externalised to a single flyweight object.

    This is some bold text.

    In the line above, you'd have two flyweights. One for the regular text and another for the four bold character instances.