Flyweight design pattern is used to minimize the memory usage with the help of an object that shares as much data as possible with other similar objects.
This pattern is very similar to the simple factory design pattern with slight modification to cache the object in a data structure so that we can return the object which is cached in the data structure if there is a request for same kind of object instead of creating it newly.
Lets say we are processing data from a text files which is received from the EMS. And we need to apply some calibration to few metrics and store them back in some location. The calibration will be applied based on the vendor firmware version and each vendor has shared a csv file which has a mapping between the firmware and the calibration factor. As loading the mapping file for each vendor and converting it into a map is a expensive operation we plan to use flyweight pattern to reuse the object if its already loaded.
We will have a interface VendorCalibration and an separate implementation of this for each vendor like huw,brocade and cisco. The flyweight design pattern is implemented through the CalibrationFactory which stores the data in a map in memory and returns the same if there is a request.
Lets jump into the code
We will start of with VendorCalibration and its implementation . I have not added the logic into the code to make the code simpler and also to focus on the usage of design pattern
public abstract class VendorCalibration { // I have not added the code to load the file and convert the data into the // map for simplicity purpose. The key of the hashmap will be the firmware // and value will be calibration to be applied public Map<String, Double> loadCorrectionFactor(File file) { // code to load the file passed in the parameter and generate the // hashmap return new HashMap<String, Double>(); } public abstract Map<String, Double> getCalibration(); }
public class HuwCalibration extends VendorCalibration { @Override public Map<String, Double> getCalibration() { return loadCorrectionFactor(new File("Huw _calibration.csv")); } }
public class BrocadeCalibration extends VendorCalibration { @Override public Map<String, Double> getCalibration() { return loadCorrectionFactor(new File("Brocade_calibration.csv")); } }
public class CiscoCalibration extends VendorCalibration { @Override public Map<String, Double> getCalibration() { return loadCorrectionFactor(new File("Cisco_calibration.csv")); } }
Lets code the CalibrationFactory where the main logic of flyweight pattern exists
public class CalibrationFactory { private static Map<String, VendorCalibration> cache = new HashMap<String, VendorCalibration>(); public static VendorCalibration getCalibrationMapper(String vendor) { VendorCalibration vendorCalibration = cache.get(vendor); if (vendorCalibration == null) { if (vendor.equalsIgnoreCase("HUW")) { HuwCalibration huwCalibration = new HuwCalibration(); cache.put("HUW", huwCalibration); return huwCalibration; } else if (vendor.equalsIgnoreCase("CISCO")) { CiscoCalibration ciscoCalibration = new CiscoCalibration(); cache.put("CISCO", ciscoCalibration); return ciscoCalibration; } else if (vendor.equalsIgnoreCase("BROCADE")) { BrocadeCalibration brocadeCalibration = new BrocadeCalibration(); cache.put("BROCADE", brocadeCalibration); return brocadeCalibration; } else { throw new InvalidParameterException(); } } else { return vendorCalibration; } } }
Driver Code
public class Driver { public static void main(String[] args) { String vendor = "HUW"; String version = "1.1.34.fs"; VendorCalibration vendorCalibration = CalibrationFactory.getCalibrationMapper(vendor); Double calibrationFactor = vendorCalibration.getCalibration().get(version); } }