In one of my previous projects I got the chance to implement this pattern. Generally this pattern is not talked much but in many projects there are good chances that you can take the advantage of this pattern immensely. If you are using Spring technology in your project then it is implemented internally by itself and you don’t have to implement this separately. But there are many projects that do not use Spring and memory is a concern.

Yes, you guessed it right. The main advantage of using Flyweight Design Pattern is to reduce object creation and reuse the existing ones. As described in the book Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma et al. ( Addison-Wesley, 1995 ) at page 195 (Also called GoF: Gang of Four): “Use sharing to support large numbers of fine grained objects efficiently”.

The technology stack for the previous project was JSF, Tiles and Hibernate. We used POJO for our Manager classes (Service classes) and DAO classes. A project can have many Manager classes and DAO Classes and let say the application is meant for 260 – 340 users with 2 GB of RAM allocated to your application on the server. In such situations you need to design your application in a way that it uses memory optimally. Talking about memory optimization in your application, Flyweight Pattern is the ideal choice. In this article I will demonstrate the usage of this pattern. One important point that you need to rememeber is that objects that you intend to share within multiple threads/requests should be thread-safe, otherwise you will face consistency issues.
package com.test.factory;
import java.util.Hashtable;
public class ManagerFactory {
/**
* Contains references of Manager that has been instantiated.
*/
private Hashtable managerReferenceTable = new Hashtable();
/**
* Contains the reference of ManagerFactory
*/
private static ManagerFactory facadeInstance;
/**
* Private Constructor.
*
*/
private ManagerFactory() {
}
/**
* Returns the instance of ManagerFactory
*
* @return
*/
public static synchronized ManagerFactory getInstance() {
if (facadeInstance == null) {
facadeInstance = new ManagerFactory();
}
return facadeInstance;
}
/**
* This method returns the reference of a Manager. It checks if it is
* already created and returns the same reference otherwise it create a new
* object of the Manager and returns the newly created object.
*
* @param managerClazz
* @return
*/
private Manager instantiateManager(Class managerClazz) {
Manager manager;
String clazzName = managerClazz.getName();
// check if manager already instantiated earlier.
if ((manager = (Manager) managerReferenceTable.get(clazzName)) != null) {
return manager;
} else {
// if not created earlier then instantiate a new object of the
// manager and store the reference in the “managerReferenceTable”
try {
manager = (Manager) managerClazz.newInstance();
managerReferenceTable.put(clazzName, manager);
return manager;
} catch (Exception ex) {
// throw exception if not able to instantiate.
throw new IllegalStateException(“Unable to create instance of “
+ managerClazz + ” Manager Class”);
}
}
}
/**
* Returns instance of OrderManager
*
* @return
*/
public OrderManager getReferenceDataManager() {
return (OrderManager) instantiateManager(OrderManagerImpl.class);
}
/**
* Returns instance of InventoryManager
*
* @return
*/
public InventoryManager getInventoryManager() {
return (InventoryManager) instantiateManager(InventoryManagerImpl.class);
}
}
 Java |  copy code |? 
01
package com.test.factory;
02
 
03
import java.util.Hashtable;
04
 
05
public class ManagerFactory {
06
 
07
 /**
08
 * Contains references of Manager that has been instantiated.
09
 */
10
 private Hashtable managerReferenceTable = new Hashtable();
11
 
12
 /**
13
 * Contains the reference of ManagerFactory
14
 */
15
 private static ManagerFactory facadeInstance;
16
 
17
 /**
18
 * Private Constructor.
19
 * 
20
 */
21
 private ManagerFactory() {
22
 
23
 }
24
 
25
 /**
26
 * Returns the instance of ManagerFactory
27
 * 
28
 * @return
29
 */
30
 public static synchronized ManagerFactory getInstance() {
31
 
32
 if (facadeInstance == null) {
33
   facadeInstance = new ManagerFactory();
34
 }
35
 return facadeInstance;
36
 }
37
 
38
 /**
39
 * This method returns the reference of a Manager. It checks if it is
40
 * already created and returns the same reference otherwise it create a new
41
 * object of the Manager and returns the newly created object.
42
 * 
43
 * @param managerClazz
44
 * @return
45
 */
46
 private Manager instantiateManager(Class managerClazz) {
47
 
48
  Manager manager;
49
  String clazzName = managerClazz.getName();
50
 
51
  // check if manager already instantiated earlier.
52
  if ((manager = (Manager) managerReferenceTable.get(clazzName)) != null) {
53
   return manager;
54
  } else {
55
  // if not created earlier then instantiate a new object of the
56
  // manager and store the reference in the "managerReferenceTable"
57
 
58
    try {
59
     manager = (Manager) managerClazz.newInstance();
60
     managerReferenceTable.put(clazzName, manager);
61
     return manager;
62
    } catch (Exception ex) {
63
     // throw exception if not able to instantiate.
64
     throw new IllegalStateException("Unable to create instance of "
65
     + managerClazz + " Manager Class");
66
    }
67
   }
68
 }
69
 
70
 /**
71
  * Returns instance of OrderManager
72
  * 
73
  * @return
74
  */
75
  public OrderManager getOrderManager() {
76
   return (OrderManager) instantiateManager(OrderManagerImpl.class);
77
  }
78
 
79
 /**
80
  * Returns instance of InventoryManager 
81
  * 
82
  * @return
83
  */
84
  public InventoryManager getInventoryManager() {
85
   return (InventoryManager) instantiateManager(InventoryManagerImpl.class);
86
  }
87
}

Now the above code demonstrates how Flyweight pattern is implemented. In this implementation of Factory pattern, it maintains a Hashtable. I used Hashtable intentionally because it is synchronized. Initially this table will be empty but gradually will contain different Manager objects, one object for a type. Whenever a consumer requests for a Manager object of type OrderManager, this Factory implementation will check whether any instance of the same type has already been created and if it already exists in the Hashtable it will return the manager object. In case it is not able to find one then the Factory will create a new instance and save it in its Hashtable instance with fully qualified name as Key and object created as Value.

The direct benefit of using this pattern is that even during the peak time this will create only single instance per type that you have defined your Factory class to cater. This code has been tested under different circumstances and successfully running in production.

You can further improve the above code for performance as per your requirements. Like you can use WeakHashMap instead of Hashtable so that manager objects that are not being used can be garbage-collected. You can also synchronize code to further than the code above.

More synchronized code

 Java |  copy code |? 
01
package com.test.factory;
02
 
03
import java.util.Hashtable;
04
 
05
public class ManagerFactory {
06
 
07
 /**
08
  * Contains references of Manager that has been instantiated.
09
  */
10
  private Hashtable managerReferenceTable = new Hashtable();
11
 
12
 /**
13
  * Contains the reference of ManagerFactory
14
  */
15
  private static ManagerFactory facadeInstance;
16
 
17
 /**
18
  * Private Constructor.
19
  * 
20
  */
21
  private ManagerFactory() {
22
 
23
  }
24
 
25
  /**
26
   * Returns the instance of ManagerFactory
27
   * 
28
   * @return
29
   */
30
   public static synchronized ManagerFactory getInstance() {
31
 
32
     if (facadeInstance == null) {
33
       facadeInstance = new ManagerFactory();
34
     }
35
     return facadeInstance;
36
   }
37
 
38
   /**
39
    * This method returns the reference of a Manager. It checks if it is
40
    * already created and returns the same reference otherwise it create a new
41
    * object of the Manager and returns the newly created object.
42
    * 
43
    * @param managerClazz
44
    * @return
45
    */
46
    private Manager instantiateManager(Class managerClazz) {
47
 
48
      Manager manager;
49
      String clazzName = managerClazz.getName();
50
 
51
      // check if manager already instantiated earlier.
52
      if ((manager = (Manager) managerReferenceTable.get(clazzName)) != null) {
53
        return manager;
54
      } else {
55
      // if not created earlier then instantiate a new object of the
56
      // manager and store the reference in the "managerReferenceTable"
57
         synchronized (this) {
58
           if ((manager = (Manager) managerReferenceTable.get(clazzName)) == null) {
59
              try {
60
                   manager = (Manager) managerClazz.newInstance();
61
                   managerReferenceTable.put(clazzName, manager);
62
                   return manager;
63
              } catch (Exception ex) {
64
                // throw exception if not able to instantiate.
65
                 throw new IllegalStateException(
66
                   "Unable to create instance of " + managerClazz + " Manager Class");
67
              }
68
 
69
           } else {
70
              return manager;
71
         }
72
 
73
      }
74
 
75
   }
76
 
77
 }
78
 
79
 /**
80
  * Returns instance of OrderManager
81
  * 
82
  * @return
83
  */
84
  public OrderManager getOrderManager() {
85
   return (OrderManager) instantiateManager(OrderManagerImpl.class);
86
  }
87
 
88
  /**
89
   * Returns instance of InventoryManager
90
   * 
91
   * @return
92
   */
93
   public InventoryManager getInventoryManager() {
94
    return (InventoryManager) instantiateManager(InventoryManagerImpl.class);
95
   }
96
}
Sharable with
  • Digg
  • Facebook
  • Google Bookmarks
  • Diigo
  • MySpace
  • StumbleUpon
  • Technorati
  • del.icio.us
  • Reddit
  • Twitter
  • DZone
  • email
  • Yahoo! Bookmarks
  • Yahoo! Buzz
  • blogmarks
  • MSN Reporter
  • PDF