In the context of the Gang of Four (GoF) design patterns, the Flyweight pattern is utilized to reduce memory usage when dealing with a large number of similar objects. It achieves this by sharing as much data as possible with similar objects.
While the Flyweight pattern itself doesn't explicitly require a Factory Method or a Factory class for its implementation, it's often beneficial and practical to use a Factory in conjunction with the Flyweight pattern.
The reason for this is that the Factory can manage the creation of flyweight objects and ensure their proper sharing. In other words, before creating a new flyweight object, the Factory can check if an identical object already exists. If it does, the existing object is returned. If it doesn't, a new object is created, added to the pool, and then returned. This process ensures that identical objects are shared, not duplicated, which is the primary goal of the Flyweight pattern.
Therefore, in practice, the Factory class (or a Factory method) is often seen as a critical component of the Flyweight pattern structure. This Factory manages the creation and retrieval of flyweight objects, ensuring that sharing is maximized, and memory usage is minimized.
Here is a simplified outline of how a Factory class might be used with the Flyweight pattern:
class FlyweightFactory {
private Map<String, Flyweight> flyweights = new HashMap<String, Flyweight>();
public Flyweight getFlyweight(String key) {
if (flyweights.containsKey(key)) {
return flyweights.get(key);
} else {
Flyweight flyweight = new Flyweight(key);
flyweights.put(key, flyweight);
return flyweight;
}
}
}
In this example, FlyweightFactory serves as a manager that prevents unnecessary duplication of Flyweight objects. When a request is made for a flyweight object, the getFlyweight method checks if such an object already exists. If so, the existing object is returned; if not, a new one is created, stored, and then returned. In conclusion, while not explicitly required by the definition of the Flyweight pattern, a Factory Method or Factory class often plays a critical role in the effective implementation of the pattern.
Flyweights require a Factory Method or a Factory class to create them. The Factory class keeps track of the Flyweights that already exist. When it is asked to create a new Flyweight, the Factory class first checks to see whether a matching Flyweight exists. If so, it returns a pointer to the old Flyweight. This requires the Factory class to maintain a searchable list of existing Flyweights. In some cases you may want to wait until a Flyweight is first requested before constructing it. In other cases, you may find it simpler to preallocate all the possible Flyweights. The basic structure looks like this:
This diagram uses one concrete Flyweight class. In some situations, necessary flexibility is achieved by making the Flyweight class abstract, then providing concrete implementations. One advantage to this approach is that you can use both shared and unshared Flyweights that respond to the same messages. This can be useful in mixed situations in which you might have several thousand copies of one Flyweight as well as a few hundred unique Flyweights.