Design Patterns Tutorial
A tutorial on GOF design patterns. This tutorial is for beginners who are going to learn design patterns for the first time. Each pattern is expalined with suitable examples.
Subscribe to Startertutorials.com's YouTube channel for different tutorial and lecture videos.

Categories: Structural Patterns. No Comments on Flyweight Pattern in Design Patterns a Java Example
0
(0)

Flyweight pattern is used to share for supporting large number of fine-grained objects efficiently. Let’s look at this design pattern in detail.

 

Flyweight pattern’s Intent

To use sharing for supporting large number of fine-grained objects efficiently.

 

Flyweight pattern’s Motivation

Some programs require a large number of objects that have some shared state among them. Consider for example a game of war, were there is a large number of soldier objects; a soldier object maintain the graphical representation of a soldier, soldier behavior such as motion, and firing weapons, in addition soldier’s health and location on the war terrain.

 

Creating a large number of soldier objects is a necessity however it would incur a huge memory cost. Note that although the representation and behavior of a soldier is the same their health and location can vary greatly.


Subscribe to our monthly newsletter. Get notified about latest articles, offers and contests.


 

Flyweight pattern’s Applicability

Apply flyweight pattern when all of the following are true:

  • An application uses a large number of objects.
  • Storage costs are high because of the sheer quantity of objects.
  • Most object state can be made extrinsic.
  • Many groups of objects may be replaced by relatively few shared objects once extrinsic state is removed.
  • The application doesn’t depend upon object identity.

 

Flyweight pattern’s Structure

The structure of flyweight pattern is shown below:

Flyweight Pattern Structure

 

Participants

The participants in the flyweight pattern are:

  • Flyweight: Declares an interface through which flyweights can receive and act on extrinsic state.
  • ConcreteFlyweight: Implements the Flyweights interface and adds storage for intrinsic state, if any. A ConcreteFlyweight object must be sharable.
  • UnsharedConcreteFlyweight: Not all Flyweight subclasses need to be shared. The Flyweight interface enables sharing, it doesn’t enforce it.
  • FlyweightFactory: Creates and manages flyweight objects. Ensures that flyweights are shared properly.
  • Client: Maintains a reference to flyweight(s). Computes or stores the extrinsic state of flyweight(s).

 

Collaborations

  • State that a flyweight needs to function must be characterized as either intrinsic or extrinsic. Intrinsic state is stored in the ConcreteFlyweight object; extrinsic state is stored or computed by Client objects. Clients pass this state to the flyweight when they invoke its operations.

 

  • Clients should not instantiate ConcreteFlyweights directly. Clients must obtain ConcreteFlyweight objects exclusively from the FlyweightFactory object to ensure they are shared properly.

 

Flyweight pattern’s Consequences

Flyweights may introduce run-time costs associated with transferring, finding, and/or computing extrinsic state, especially if it was formerly stored as intrinsic state. However, such costs are offset by space savings, which increase as more flyweights are shared.

 

Storage savings are a function of several factors:

  • The reduction in the total number of instances that comes from sharing
  • The amount of intrinsic state per object
  • Whether extrinsic state is computed or stored.

 

Flyweight pattern’s Implementation

Following issues must be considered while implementing flyweight pattern:

  1. Removing extrinsic state. The pattern’s applicability is determined largely by how easy it is to identify extrinsic state and remove it from shared objects. Removing extrinsic state won’t help reduce storage costs if there are as many different kinds of extrinsic state as there are objects before sharing.

 

  1. Managing shared objects. Because objects are shared, clients shouldn’t instantiate them directly. FlyweightFactory lets clients locate a particular flyweight. FlyweightFactory objects often use an associative store to let clients look up flyweights of interest.

 

Sample Code (Java Example)

For applying flyweight pattern, we need to create a Flyweight factory that returns the shared objects. For our example, lets say we need to create a drawing with lines and Ovals. So we will have an interface Shape and its concrete implementations as Line and Oval. Oval class will have intrinsic property to determine whether to fill the Oval with given color or not whereas Line will not have any intrinsic property.

 

Flyweight Interface and Concrete Classes:

//Shape.java
import java.awt.Color;
import java.awt.Graphics;
 
public interface Shape {
 
    public void draw(Graphics g, int x, int y, int width, int height,
            Color color);
}

 

//Line.java
import java.awt.Color;
import java.awt.Graphics;
 
public class Line implements Shape {
 
    public Line(){
        System.out.println("Creating Line object");
        //adding time delay
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void draw(Graphics line, int x1, int y1, int x2, int y2,
            Color color) {
        line.setColor(color);
        line.drawLine(x1, y1, x2, y2);
    }
 
}

 

//Oval.java
import java.awt.Color;
import java.awt.Graphics;
 
public class Oval implements Shape {
     
    //intrinsic property
    private boolean fill;
     
    public Oval(boolean f){
        this.fill=f;
        System.out.println("Creating Oval object with fill="+f);
        //adding time delay
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void draw(Graphics circle, int x, int y, int width, int height,
            Color color) {
        circle.setColor(color);
        circle.drawOval(x, y, width, height);
        if(fill){
            circle.fillOval(x, y, width, height);
        }
    }
 
}

 

Notice that delay is intentionally introduced in creating the Object of concrete classes to make the point that flyweight pattern can be used for Objects that takes a lot of time while instantiated.

 

The flyweight factory will be used by client programs to instantiate the Object, so we need to keep a map of Objects in the factory that should not be accessible by client application. Whenever client program makes a call to get an instance of Object, it should be returned from the HashMap, if not found then create a new Object and put in the Map and then return it. We need to make sure that all the intrinsic properties are considered while creating the Object.

 

Our flyweight factory class looks like below code:

//ShapeFactory.java
import java.util.HashMap;
 
public class ShapeFactory {
 
    private static final HashMap<ShapeType,Shape> shapes = new HashMap<ShapeType,Shape>();
 
    public static Shape getShape(ShapeType type) {
        Shape shapeImpl = shapes.get(type);
 
        if (shapeImpl == null) {
            if (type.equals(ShapeType.OVAL_FILL)) {
                shapeImpl = new Oval(true);
            } else if (type.equals(ShapeType.OVAL_NOFILL)) {
                shapeImpl = new Oval(false);
            } else if (type.equals(ShapeType.LINE)) {
                shapeImpl = new Line();
            }
            shapes.put(type, shapeImpl);
        }
        return shapeImpl;
    }
     
    public static enum ShapeType{
        OVAL_FILL,OVAL_NOFILL,LINE;
    }
}

 

Below is a sample program that consumes flyweight pattern implementation:

//DrawingClient.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
 
import com.journaldev.design.flyweight.ShapeFactory.ShapeType;
 
public class DrawingClient extends JFrame{
 
    private static final long serialVersionUID = -1350200437285282550L;
    private final int WIDTH;
    private final int HEIGHT;
 
    private static final ShapeType shapes[] = { ShapeType.LINE, ShapeType.OVAL_FILL,ShapeType.OVAL_NOFILL };
    private static final Color colors[] = { Color.RED, Color.GREEN, Color.YELLOW };
     
    public DrawingClient(int width, int height){
        this.WIDTH=width;
        this.HEIGHT=height;
        Container contentPane = getContentPane();
 
        JButton startButton = new JButton("Draw");
        final JPanel panel = new JPanel();
 
        contentPane.add(panel, BorderLayout.CENTER);
        contentPane.add(startButton, BorderLayout.SOUTH);
        setSize(WIDTH, HEIGHT);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
 
        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                Graphics g = panel.getGraphics();
                for (int i = 0; i < 20; ++i) {
                    Shape shape = ShapeFactory.getShape(getRandomShape());
                    shape.draw(g, getRandomX(), getRandomY(), getRandomWidth(),
                            getRandomHeight(), getRandomColor());
                }
            }
        });
    }
     
    private ShapeType getRandomShape() {
        return shapes[(int) (Math.random() * shapes.length)];
    }
 
    private int getRandomX() {
        return (int) (Math.random() * WIDTH);
    }
 
    private int getRandomY() {
        return (int) (Math.random() * HEIGHT);
    }
 
    private int getRandomWidth() {
        return (int) (Math.random() * (WIDTH / 10));
    }
 
    private int getRandomHeight() {
        return (int) (Math.random() * (HEIGHT / 10));
    }
 
    private Color getRandomColor() {
        return colors[(int) (Math.random() * colors.length)];
    }
 
    public static void main(String[] args) {
        DrawingClient drawing = new DrawingClient(500,600);
    }
}

 

If you run above client program, you will notice the delay in creating first Line Object and Oval objects with fill as true and false. After that the program executes quickly since its using the shared objects.

 

Flyweight pattern’s Known Uses

Following are the examples in Java API where flyweight pattern is used:

java.lang.Integer#valueOf(int) (also on Boolean, Byte, Character, Short and Long)

 

Related Patterns

The Flyweight pattern is often combined with the Composite pattern to implement a logically hierarchical structure in terms of a directed-acyclic graph with shared leaf nodes.

 

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

 

Non-Software Example

The Flyweight uses sharing to support large numbers of objects efficiently. The public switched telephone network is an example of a Flyweight. There are several resources such as dial tone generators, ringing generators, and digit receivers that must be shared between all subscribers.

 

A subscriber is unaware of how many resources are in the pool when he or she lifts the hand set to make a call. All that matters to subscribers is that dial tone is provided, digits are received, and the call is completed.

 

Flyweight Pattern Real World Example

 

How useful was this post?

Click on a star to rate it!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?

Suryateja Pericherla

Suryateja Pericherla, at present is a Research Scholar (full-time Ph.D.) in the Dept. of Computer Science & Systems Engineering at Andhra University, Visakhapatnam. Previously worked as an Associate Professor in the Dept. of CSE at Vishnu Institute of Technology, India.

He has 11+ years of teaching experience and is an individual researcher whose research interests are Cloud Computing, Internet of Things, Computer Security, Network Security and Blockchain.

He is a member of professional societies like IEEE, ACM, CSI and ISCA. He published several research papers which are indexed by SCIE, WoS, Scopus, Springer and others.

Note: Do you have a question on this article or have a suggestion to make this article better? You can ask or suggest us by filling in the below form. After commenting, your comment will be held for moderation and will be published in 24-48 hrs.

Leave a Reply

Your email address will not be published. Required fields are marked *