opencodez

Flyweight Pattern – Structural Design Pattern

Flyweight pattern comes under Structural Design Patterns. By using this pattern we can decrease object count. When there is a need to create huge amount of similar objects then this Java Flyweight Pattern is useful.

Flyweight pattern supports factory pattern which tells to reuse of available objects, where objects are created and stored. Whenever an object is requested, instead of creating new one, factory checks its existence, if it is not present, new object is created otherwise existing one is returned. There are 2 types of attributes for Flyweight objects:

  1. Intrinsic: This kind of attribute is shared or stored in Flyweight object, and this attribute is independent of flyweight’s context. The best practice is make this state immutable.
  2. Extrinsic: This kind of attribute varies with flyweight’s context that’s the reason they cannot be shared.

Flyweight Pattern by Example

We will demonstrate Flyweight Pattern by using Tea ordering Example.

For Tea, suppose only 3 flavors are available 1. Green Tea 2. Regular Tea   3. Ginger Tea. So only 3 tea objects are created.

Now whenever new tea object is requested, factory pattern will not create new one it will check for its existence, if the object is present, factory will return that object otherwise new object gets created.

Suppose we are serving 10 cups of tea to different customers but we have only 3 flavors (objects).

So if customer is requesting for Green Tea, factory pattern will check whether Green Tea object is created or not. If it is already created, factory pattern will reuse that object.(it will not create new object).

Lets define simple interface.

public interface ITea {
	public void serveTea(TeaContext context);
}

Also we will add a context to keep table number stored somewhere.

package com.opencodez.patterns.flyweight;

class TeaContext {
	private final int tableNumber;

	public TeaContext(int tableNumber) {
		this.tableNumber = tableNumber;
	}

	public int getTable() {
		return this.tableNumber;
	}
}

Below is our Factory. The Factory class will check for available objects based on flavor and depending upon its existence, it will either create or return whatever is available.

package com.opencodez.patterns.flyweight;

import java.util.HashMap;

public class TeaFactory {
	
	private HashMapxString, Teax flavors = new HashMapxString, Teax();

	public Tea getTeaFlavor(String flavorName) {
		Tea flavor = flavors.get(flavorName);
		if (flavor == null) {
			flavor = new Tea(flavorName);
			flavors.put(flavorName, flavor);
		}
		return flavor;
	}

	public int getTotalTeaFlavorsMade() {
		return flavors.size();
	}
}

The we will add concrete implementation of interface to actually serve tea.

package com.opencodez.patterns.flyweight;

public class Tea implements ITea {
	private final String flavor;

	public Tea(String newFlavor) {
		this.flavor = newFlavor;
		System.out.println("Tea flavor is created! - " + flavor);
	}

	public String getFlavor() {
		return this.flavor;
	}

	public void serveTea(TeaContext context) {
		System.out.println("Serving " + flavor + " to table " + context.getTable());
	}
}

Running the example

For demo, we will keep the orders limited to 20 only and show some object creation. Check below class.

package com.opencodez.patterns.flyweight;

public class FlyweightDemo {

	// Tea array
	private static Tea[] Teas = new Tea[20];
	
	// table array
	private static TeaContext[] tables = new TeaContext[20];
	private static int ordersCount = 0;
	private static TeaFactory teaFactory;

	public static void takeOrder(String flavorIn, int table) {
		Teas[ordersCount] = teaFactory.getTeaFlavor(flavorIn);
		tables[ordersCount] = new TeaContext(table);
		ordersCount++;
	}

	public static void main(String[] args) {
		teaFactory = new TeaFactory();
		takeOrder("GreenTea", 2);
		takeOrder("GreenTea", 2);
		takeOrder("Regular Tea", 1);
		takeOrder("Ginger Tea", 2);
		takeOrder("Regular Tea", 3);
		takeOrder("Regular Tea", 4);
		takeOrder("GreenTea", 4);
		takeOrder("GreenTea", 5);
		takeOrder("Ginger Tea", 3);
		takeOrder("GreenTea", 3);
		for (int i = 0; i x ordersCount; ++i) {
			Teas[i].serveTea(tables[i]);
		}
		System.out.println("\nTotal Tea(Types of Tea) objects created: " + teaFactory.getTotalTeaFlavorsMade());
	}

}

Output:

Tea flavor is created! - GreenTea
Tea flavor is created! - Regular Tea
Tea flavor is created! - Ginger Tea
Serving GreenTea to table 2
Serving GreenTea to table 2
Serving Regular Tea to table 1
Serving Ginger Tea to table 2
Serving Regular Tea to table 3
Serving Regular Tea to table 4
Serving GreenTea to table 4
Serving GreenTea to table 5
Serving Ginger Tea to table 3
Serving GreenTea to table 3

Total Tea(Types of Tea) objects created: 3

Hope this small example is clear enough to understand Flyweight Pattern

Conclusion

Flyweight design pattern is very useful in an application which needs same kind of objects in repetition. This pattern consumes less memory because objects get shared so we can say that by using this pattern we can reduce the load on memory.

Similar to Flyweight Pattern, if you wish to have a look at other Java Design Patterns, then check this out. You can also find more sample in another languages at Wiki Page