Flyweight Pattern in Java

Type : Structural Design Pattern

Summary


Flyweight design pattern deals with sharing some of the internal details between different object instances, so that we can save memory by basically using less duplication of the attributes across its instances.

Details


In Flyweight design pattern the Object attributes are categorized into its extrinsic and intrinsic attributes. Extrinsic attributes are the attributes that can be considered as sharable across other instances. Intrinsic attributes are the attributes that are unique for each object, like the primary key, unique fields etc.
In Flyweight design we can improve the memory footprint by reusing the extrinsic properties in multiple instances of the object.

Flyweight can use Cache to store the different Extrinsic states. Factory method can be used to create the instances of the Extrinsic object and stored in cache.

Example


For instance say we are designing a Vehicle in OOP. Now each instance of the Vehicle will have some unique characteristics like its serial number, registration number.
Also we can notice that each vehicle instances will share something very similar like the Body Type, Engine etc. across multiple instances. 
We will consider the Engine to be extrinsic property which can be shared across different instances of Vehicle
We will consider the serial number as intrinsic property.

Vehicle is the interface representing vehicle
Vehicle contains an instance fo Engine
Engine is an interface
We have two type of Engine implemented by ElectricEngine and GasolineEngine
EngineFactory is a cache holding different types of Engine.
CarImpl implements Vehicle. It has a reference to Engine object.

Class Diagram



Sample Code


public interface Engine {
  
  public String getEngineName();

  public String getType();

  public int getHorsePower();

  public String getMaxSpeed();
}



public interface Vehicle {

  public String getModelName();

  public String getYear();

  Engine getEngine();

}

public class ElectricEngine implements Engine {

  private String engineName;
  private String engineType;

  public ElectricEngine(String name) {
    this.engineName = name;
    this.engineType = "Electric";
  }

  @Override
  public String getEngineName() {
    return engineName;
  }

  @Override
  public int getHorsePower() {
    return 200;
  }

  @Override
  public String getMaxSpeed() {
    return "110 MPH";
  }
  
  public String getEngineType() {
    return engineType;
  }

  @Override
  public String getType() {
    return this.engineType;
  }

}

public class GasolineEngine implements Engine {

  private String engineName;
  private String engineType;

  public GasolineEngine(String name) {
    this.engineName = name;
    this.engineType = "Gasoline";
  }

  @Override
  public String getEngineName() {
    return this.engineName;
  }

  @Override
  public int getHorsePower() {
    return 200;
  }

  @Override
  public String getMaxSpeed() {
    return "170 MPH";
  }

  public String getEngineType() {
    return engineType;
  }
  
  @Override
  public String getType() {
    return this.engineType;
  }

}



public class EngineFactory {
  private static Map engineCache = new HashMap();

  public static Engine getEngine(String engineName) {
    if (engineCache.containsKey(engineName)) {
      return engineCache.get(engineName);
    } else {
      if (engineName.startsWith("Electric"))
        return getElectricEngine(engineName);
      else
        return getGasEngine(engineName);
    }
  }

  public static Engine getGasEngine(String engineName) {
    GasolineEngine gasEngine = new GasolineEngine(engineName);
    engineCache.put(engineName, gasEngine);
    return gasEngine;
  }

  public static Engine getElectricEngine(String engineName) {
    ElectricEngine gasEngine = new ElectricEngine(engineName);
    engineCache.put(engineName, gasEngine);
    return gasEngine;
  }

  public static int getTotalEnginesMade() {
    return engineCache.size();
  }

}

public class CarImpl implements Vehicle {

  private String model;
  private String year;
  private String serialNumber;
  private Engine engine;

  public CarImpl(String model, String year, String slNumber, String type) {
    this.model = model;
    this.year = year;
    this.serialNumber = slNumber;
    this.engine = EngineFactory.getEngine(type);
  }

  @Override
  public String getModelName() {
    return this.model;
  }

  @Override
  public String getYear() {
    return this.year;
  }

  @Override
  public Engine getEngine() {
    return this.engine;
  }

  public String getSerialNumber() {
    return this.serialNumber;
  }

  @Override
  public String toString() {
    return "model= " + this.model + " year=" + this.year + " slNo=" + this.serialNumber
        + " engineType=" + this.engine.getType();
  }
}

Advantages


Memory consumption can be reduced by sharing Extrinsic states across objects.

Disadvantages

Flyweight weight increases the complexity of Object structure.

Comments

Popular posts from this blog

Difference between volatile and synchronized

Converting Java Map to String

Masking Credit Card number in Java