Sharing and reusing objects with the flyweight design pattern in Java
The Builder pattern is used to create many objects, whereby the Flyweight pattern is about sharing such a collection of objects. The flyweight design pattern is a structural pattern used to improve memory usage and performance (i.e. due to shorter and less frequent garbage collections). Here, instead of creating a large number of objects, we reuse the objects that are already created. With fewer objects, your application could fly.
Q. Can you give some examples of the usage of the flyweight design pattern in Java?
A.
Example 1: In Java, String objects are managed as flyweight. Java puts all fixed String literals into a literal pool. For redundant literals, Java keeps only one copy in the pool.
String author = "Little brown fox"; String authorCopy = "Little brown fox"; if(author == authorCopy) { System.out.println("referencing the same object"); }The above code snippet will print "referencing the same object". Even though the two String objects are created separately, under the covers Java is storing them in the same location, to save space by applying the flyweight design pattern.
Example 2: The Wrapper classes like Integer, Float, Decimal, Boolean, and many other classes having the valueOf static factory method applies the flyweight design pattern to conserve memory by reusing the objects.
public class FlyWeightWrapper { public static void main(String[] args) { Integer value1 = Integer.valueOf(5); Integer value2 = Integer.valueOf(5); if (value1 == value2) { System.out.println("referencing the same object"); } } }
The above code snippet will print "referencing the same object".
Q. How will you apply this pattern in the following scenario?
You have a scheduling application where a number of different time slots are used in 15 minute intervals in various online reporting. It contains hour and minute slots as in 10:15, 10:30, etc. The objects need to be immutable and reusable.
A. Here is the sample code that makes use of the getInstance(...) static factory method to create objects.
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; //no setters, immutable object //final class -- don't let outsiders extend public final class Schedule { private byte hour; private byte minute; private static Map<String,Schedule> schedules = new ConcurrentHashMap<String,Schedule>(); // Don't let outsiders create new factories directly // can be invoked only via getInstance (byte hour, byte minute) method private Schedule(byte hour, byte minute) { this.hour = hour; this.minute = minute; } public byte getHour() { return hour; } public byte getMinute() { return minute; } public static Schedule getInstance(byte hour, byte minute) { String key = hour + ":" + minute; //check the object pool first Schedule schedule = schedules.get(key); //if not found in the pool, create a new instance if (schedule == null) { schedule = new Schedule(hour, minute); // add it to the pool, for later reuse schedules.put(key, schedule); } return schedule; } }
Q. Are there any alternatives to using an object or resource pool to conserve memory in Java?
A. Yes, you can use a ThreadLocal object to create an object per thread. This approach is useful when creation of a particular object is not trivial and the objects cannot be shared between threads. For example, java.util.Calendar and java.text.SimpleDateFormat. Because these are heavy objects that often need to be set up with a format or locale, it’s very tempting to create it with a static initializer and stick the instance in a static field. Both of these classes use internal mutable state when doing date calculations or formatting/parsing dates. If they are called from multiple threads at the same time, the internal mutable state will most likely do unexpected things and give you wrong answers. In simple terms, this will cause thread-safety issues that can be very hard to debug.
Here is an example with the ThreadLocal class to create per thread heavy object applying the abstract factory and singleton design patterns.
//final class -- don't let outsiders extend public final class CalendarFactory { private ThreadLocal<calendar> calendarRef = new ThreadLocal<calendar>() { protected Calendar initialValue() { return new GregorianCalendar(); } }; private static CalendarFactory instance = new CalendarFactory(); public static CalendarFactory getFactory() { return instance; } public Calendar getCalendar() { return calendarRef.get(); } // Don't let outsiders create new factories directly private CalendarFactory() {} }
Another alternative is to create immutable objects as they are inherently thread-safe, and can be shared with multiple threads.
Other design patterns - real life examples
- When to use a builder design pattern? real life tips
- Deadlock Retry with JDK Dynamic Proxy
- Proxy design pattern implementing thread safe wrappers
- Java I/O -- the Decorator and proxy design pattern interview questions and answers
- Java design pattern interview questions and answers: strategy and factory pattern
- Sharing and reusing objects with the flyweight design pattern in Java
- Observer design pattern for publish/Subscribe model
Labels: design pattern