Flyweight Pattern

The pattern suggests a mechanism by which you can avoid creating a large number of object instances which have similar content.

The Flyweight pattern suggests separating all the intrinsic common data into a separate object referred to as a Flyweight object. The group of objects being created can share the Flyweight object. This eliminates the need for storing the same invariant, intrinsic information in every object.

Every object can be viewed as consisting of one or both of the following two sets of information:

  • Intrinsic (Internal) Information: The intrinsic information of an object is independent of the object context. That means the intrinsic information is the common information that remains constant among different instances of a given class. For example, the company information on a visiting card is the same for all employees. Intrinsic state is stored in the flyweight.
  • Extrinsic (External) Information: The extrinsic information of an object is dependent upon and varies with the object context. That means the extrinsic information is unique for every instance of a given class. For example, the employee name and title are extrinsic and unique on a visiting card

Implementation

  • There exists only one object of a given flyweight kind and is shared by all the other appropriate objects.
  • Client objects should not be allowed to create flyweight instances directly.

This is a simple flyweight implementation using maps and a simple internal factory:

public class FlyWeight {
    private static Map<String,FlyWeight> flyweight = new HashMap<String,FlyWeight>();
 
    private FlyWeight(){
    }
 
    private FlyWeight(String type){
        //we can perform extra activity here for the actual creation of flyweight
    }
 
    //simple factory
    public synchronized static FlyWeight getFlyWeight(String flyweightType){
 
        if (flyweight.containsKey(flyweightType)) return flyweight.get(flyweightType);
        else{
            FlyWeight newone = new FlyWeight(flyweightType);
            flyweight.put(flyweightType,newone);
            return newone;
        }
    }
}

Another example with a more separate factory comes below. Assume company and address are things than can be share for a division:

public interface FlyWeight {
    public String getCompany();
    public String getAddress();
}
 
public class FlyWeightFactory {
    private HashMap<String,FlyWeight> lstFlyweight;
    private static FlyWeightFactory factory =  new FlyWeightFactory();
 
    private FlyWeightFactory() {
        lstFlyweight = new HashMap<String,FlyWeight>();
    }
 
    public synchronized FlyWeight getFlyweight(String division) {
        if (! lstFlyweight.containsKey(division)) {
            FlyWeight fw = new ConcreteFlyweight(division);
            lstFlyweight.put(division, fw);
            return fw;
        } else {
            return (FlyWeight) lstFlyweight.get(division);
        }
    }
 
    public static FlyWeightFactory getInstance() {
            return factory;
    }
 
    //Concrete flyweights need not be inner necessarily
    private class ConcreteFlyweight implements FlyWeight {
        private String address;
        private String company;
 
        public ConcreteFlyweight (String division) {
            if (division == "IT"){
                this.address = "xyz";
                this.company = "abc";
 
            }else if (division == "Billing") {
                this.address = "ert";
                this.company = "dgk";
            }
        }
        @Override
        public String getAddress() {
            return this.address;
        }
 
        @Override
        public String getCompany() {
            return this.company;
        }
    }
}
flyw.jpg

In this picture:
ConcreteFlyweight adds storage for shared intrinsic state. UnsharedConcreteFlyweight is not sharable. The Flyweight interface enables sharing but it doesn't force it. It's common for UnsharedConcreteFlyweight objects to have ConcreteFlyweight objects as children at some level in the flyweight object structure.

Related Patterns

The Flyweight pattern is often combined with the Composite pattern to represent a hierarchical structure as a graph with shared leaf nodes. A consequence of sharing is that flyweight leaf nodes cannot store a pointer to their parent. Rather, the parent pointer is passed to the flyweight as part of its extrinsic state. This has a major impact on how the objects in the hierarchy communicate with each other.

It's often best to implement State and Strategy objects as flyweights.

//TODO some more examples are needed here specially on UnsharedConcreteFlyweight. See Ref 1 book.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License