The Flyweight Design Pattern is one of the structural patterns introduced by the GOF. The Flyweight Pattern is about creating a pool of objects that allows sharing already existing objects and causing the application to consume less memory.

So this pattern does the following two things because the pattern creates objects once and then saves them to a pool:
  1. Increases application performance in terms of object creation since there is no requirement of creating an object for every request.

  2. Causes the application to consume less memory, since the object already exists in memory and no new object must be created because of the pool.

Ultimately flyweight patterns make the application efficient in terms of memory and processing.

Basic UML class Diagram of Design Pattern

The following image shows the class diagram of the basic Flyweight Design Pattern.

UML class Diagram

Note: UnSharedFlyweight is not always required, it depends on requirements, but SharedFlyweight is always required when you use the flyweight pattern.

The following code is the implementation of the Flyweight Design Pattern and the Class Diagram was shown above.

  1. namespace BasicFlyweightPattern
  2. {
  3. #region basic implementation
  4. public class FlyweightFactory
  5. {
  6. public static List<Item> GetStaticItemList(string key)
  7. {
  8. IFlyWeight flyWeight = null;
  9. ICacheManager _objCacheManager = CacheFactory.GetCacheManager();
  10. if (key == "A")
  11. {
  12. if (_objCacheManager.Contains("A"))
  13. {
  14. return _objCacheManager["A"] as List<Item>;
  15. }
  16. else
  17. {
  18. flyWeight = new ConcerateSharedFlyweight1();
  19. }
  20. }
  21. else if (key == "B")
  22. {
  23. if (_objCacheManager.Contains("B"))
  24. {
  25. return _objCacheManager["B"] as List<Item>;
  26. }
  27. else
  28. {
  29. flyWeight = new ConcerateSharedFlyweight2();
  30. }
  31. }
  32. var list = flyWeight.GetList();
  33. _objCacheManager.Add(key, list);
  34. return list;
  35. }
  36. }
  37. interface IFlyWeight
  38. {
  39. List<Item> GetList();
  40. }
  41. public class Item
  42. {
  43. public int id { get; set; }
  44. public string desc { get; set; }
  45. }
  46. public class ConcerateSharedFlyweight1 : IFlyWeight
  47. {
  48. private List<Item> ItemList;
  49. public ConcerateSharedFlyweight1()
  50. {
  51. ItemList = new List<Item>();
  52. }
  53. public List<Item> GetList()
  54. {
  55. ItemList.Add(new Item { id = 1, desc = "A1" });
  56. ItemList.Add(new Item { id = 2, desc = "A2" });
  57. ItemList.Add(new Item { id = 3, desc = "A3" });
  58. return ItemList;
  59. }
  60. }
  61. public class ConcerateSharedFlyweight2 : IFlyWeight
  62. {
  63. private List<Item> ItemList;
  64. public ConcerateSharedFlyweight2()
  65. {
  66. ItemList = new List<Item>();
  67. }
  68. public List<Item> GetList()
  69. {
  70. ItemList.Add(new Item { id = 1, desc = "B1" });
  71. ItemList.Add(new Item { id = 2, desc = "B2" });
  72. ItemList.Add(new Item { id = 3, desc = "B3" });
  73. return ItemList;
  74. }
  75. }
  76. class Program
  77. {
  78. static void Main(string[] args)
  79. {
  80. List<Item> list =FlyweightFactory.GetStaticItemList("A");
  81. //List<Item> list = FlyweightFactory.GetStaticItemList("B");
  82. foreach (var item in list)
  83. {
  84. Console.WriteLine(item.id.ToString() + " " + item.desc );
  85. }
  86. Console.ReadLine();
  87. }
  88. }
  89. }
The following are points to remember about the preceding code implementation:
  1. The client asks for data from FlyweightFactory by calling GetStaticItemList and passing the key as argument for getting the data.

  2. FlyweightFactory has a static method GetStaticItemList that creates an instance of concrete and gets data if the request is for the first time, for a later request it returns an existing object.

  3. FlyweightFacotry maintains a pool of existing objects using an Enterprise library caching block for sharing data among the clients, in other words different objects.

  4. In the concrete implementation of flyweight, a hardcoded list is returned but in an actual scenario this will be replaced by data from a data source.

  5. Item is a poco class, the list of which is returned from flyweight concrete classes. This class is represented by different items. The following actual scenario provides more detail.

Output

run

Here the output shows the result of A's same will use the result of B's. If the call comes a second time then the data is retuned from the cache.

Flyweight Design Pattern Example In an Actual Application

Problem Statement

A web application having a dropdown for displaying a list of Country, displaying a list of State, displaying a list of Product and so on in the dropdown and the dropdowns are part of multiple screens that are accessed by multiple users.

In this scenario, to display another kind of list for multiple user requests, the server must connect with the database server multiple times. This reduces the performance of the application and also consumes memory for creating and storing these lists.

Solution

The solution to the preceding problem is to use the Flyweight Design Pattern.

The following is a class diagram of the Flyweight pattern used in the application.

class diagram

  1. namespace FlyWeightPattern
  2. {
  3. class Program
  4. {
  5. static void Main(string[] args)
  6. {
  7. List<StaticItem> countrylist = StaticDataListFlyWeidhtFactory.GetStaticItemList("Country");
  8. foreach (var item in countrylist)
  9. {
  10. Console.WriteLine(item.id.ToString() + " " + item.Code + " " + item.Description);
  11. }
  12. Console.ReadLine();
  13. }
  14. }
  15. public class StaticDataListFlyWeidhtFactory
  16. {
  17. public static List<StaticItem> GetStaticItemList(string key)
  18. {
  19. IFlyWeightManager manager = null;
  20. ICacheManager _objCacheManager = CacheFactory.GetCacheManager();
  21. if (key == "Country")
  22. {
  23. if (_objCacheManager.Contains("Country"))
  24. {
  25. return _objCacheManager["Country"] as List<StaticItem>;
  26. }
  27. else
  28. {
  29. manager = new CountryStaticListManager();
  30. }
  31. }
  32. else if (key == "ProductType")
  33. {
  34. if (_objCacheManager.Contains("ProductType"))
  35. {
  36. return _objCacheManager["ProductType"] as List<StaticItem>;
  37. }
  38. else
  39. {
  40. manager = new ProductTypeStaticListManager();
  41. }
  42. }
  43. var list = manager.GetList();
  44. _objCacheManager.Add(key, list);
  45. return list;
  46. }
  47. }
  48. interface IFlyWeightManager
  49. {
  50. List<StaticItem> GetList();
  51. }
  52. public class CountryStaticListManager : IFlyWeightManager
  53. {
  54. private List<StaticItem> StaticItemList;
  55. public CountryStaticListManager()
  56. {
  57. StaticItemList = new List<StaticItem>();
  58. }
  59. public List<StaticItem> GetList()
  60. {
  61. StaticItemList.Add(new StaticItem { id = 1, Code = "IND", Description = "India" });
  62. StaticItemList.Add(new StaticItem { id = 2, Code = "SRL", Description = "Sri Lanka" });
  63. StaticItemList.Add(new StaticItem { id = 3, Code = "SA", Description = "South Africa" });
  64. return StaticItemList;
  65. }
  66. }
  67. public class ProductTypeStaticListManager : IFlyWeightManager
  68. {
  69. private List<StaticItem> StaticItemList;
  70. public ProductTypeStaticListManager()
  71. {
  72. StaticItemList = new List<StaticItem>();
  73. }
  74. public List<StaticItem> GetList()
  75. {
  76. StaticItemList.Add(new StaticItem { id = 1, Code = "0123", Description = "Watch" });
  77. StaticItemList.Add(new StaticItem { id = 2, Code = "0234", Description = "Shoes" });
  78. StaticItemList.Add(new StaticItem { id = 3, Code = "0345", Description = "" });
  79. return StaticItemList;
  80. }
  81. }
  82. public class StaticItem
  83. {
  84. public int id { get; set; }
  85. public string Code { get; set; }
  86. public string Description { get; set; }
  87. }
  88. }
Output

output

So the preceding code works the same as already described in the basic implementation of pattern. In the code another type of the list is fetched by passing a different key. For this implementation the keys are Country and Product. In a real application one can have more than this.

The preceding implementation follows the SOLID principle, just one exception is the Factory class that must be modifed when one wants to add a new key so it breaks the rule of single responsibility.

Note: Here the country and product list are hardcoded but in an actual program it is fetched from the database.

Conclusion

This pattern is very helpful in the scenario where one wants to create a pool of objects and share them among the clients (the clients are software programs or classes or web applications as in this example).

Note: This is my point of view regarding patterns. Please provide your feedback regarding it and also provide feedback if something you find is wrong in this.