Home
Core Java
Java
JDBC
Servlets
JSP
EJB
JMS
Struts
Spring
Hibernate
JSF
RMI
CORBA
J2ME
Performance
Tomcat
Weblogic
Design Patterns
Junit
XML
UML
DB2 & SQL
ANT
Free Gift
Contact Us

XML RSS
What is this?
Add to My Yahoo!
Add to My MSN
Add to Google
 

Structural Pattern

Flyweight Pattern

Your Ad Here

Creational patterns Structural patterns Behavioral pattern J2EE patterns
Abstract Factory Adapter  Chain of Responsibility
MVC 
Builder Bridge  Command  Business Delegate
Factory method Composite  Interpreter  Composite Entity
Prototype Decorator  Iterator  Data Access Object
Singleton Façade
Mediator  Front Controller

Flyweight  Memento  Intercepting Filter

Proxy  Observer  Service Locator


State  Transfer Object


Strategy 


Template Method



Visitor 

Flyweight Pattern



Define flyweight pattern
Make instances of classes on the fly to improve performance efficiently, like individual characters or icons on the screen.

Where to use & benefits
Need to instantiate a large amount of small and fine-grained classes.
Need icons to represent object.
An object extrinsic state can be shared by classes.
Reduce the number of objects created, decrease memory footprint and increase performance.
Increase runtime cost associated with transferring, finding, or computing extrinsic data.

Related patterns include
  • Composite, which supports recursive structures, whereas an flyweight is often applied on it.
  • Factory Method, which produces specific object upon requirement, whereas an flyweight uses it to reduce objects.
  • State, which allows an object to alter its behavior when its internal state is changed, whereas a flyweight is best implemented on it.
  • Strategy, which allows an algorithm vary independently to suit its needs, whereas a flyweight is based on such strategy.

Your Ad Here
Example of flyweight pattern
In order to share an object, we may declare an interface and an intrinsic state through which flyweights can receive and act on it. If you want to show a file system with folders to show the directories or subdirectories, you don't need to load all the files or directories at one loading time. You may show the upper level folders first. If the user clicks a folder, then load its subdirectories and files. The shared trigger is mouse-clicked. The composite pattern may be combined to define the flyweight system.

class Folder {
  void draw(..) {}
}
class FolderFactory {
   ...
   if (selected) {
      return aFolder;
   else
      return aFile;
   ...
}

...

To show how to use flyweight to reduce object creation, we will make a program to draw 1000 circles with 6 different colors. Before we customize it to a flyweight design, it is coded as follows:

import java.awt.*;
import java.awt.Color;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

class Test extends JFrame{
   private static final Color colors[] = { Color.red, Color.blue,
                                           Color.yellow, Color.orange,
                                           Color.black,  Color.white };
   private static final int WIDTH_ = 400,
                            HEIGHT = 400,
                            NUMBER_OF_CIRCLES = 1000;

   public Test() {
      Container contentPane = getContentPane();
     
      JButton button = new JButton("Draw Circle");
      final JPanel  panel  = new JPanel();

      contentPane.add(panel,  BorderLayout.CENTER);
      contentPane.add(button, BorderLayout.SOUTH);
      setSize(WIDTH,HEIGHT);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setVisible(true);

      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent event) {
            Graphics g = panel.getGraphics();

            for(int i=0; i < NUMBER_OF_CIRCLES; ++i) {
               g.setColor(getRandomColor());
               int r = getRandomR();
               g.drawOval(getRandomX(), getRandomY(), r, r);
            }
         }
      });
   }

   private int getRandomX() {
      return (int)(Math.random()*WIDTH );
   }
   private int getRandomY() {
      return (int)(Math.random()*HEIGHT);
   }
   private int getRandomR() {
      return (int)(Math.random()*(HEIGHT/10));
   }
   private Color getRandomColor() {
      return colors[(int)(Math.random()*colors.length)];
   }
   public static void main(String[] args) {
      Test test = new Test();
   }  
}

Copy, paste above code, and run it to see the functionality.
Output :
 

Flyweight pattern
 

Note that the above program doesn't take advantage of reusability of OOP. We will customize it and make a Circle object, so the Circle object can be reused.

class Circle {
   private Color color;

   public Circle(Color color) {
      this.color = color;
   }
   public void draw(Graphics g, int x, int y, int r) {
      g.setColor(color);
      g.drawOval(x, y, r, r);
   }
}

Then we rewrite the program. It is possible for people to rewrite with Circle object in the following way:

import java.awt.*;
import java.awt.Color;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

class Test extends JFrame{
   private static final Color colors[] = { Color.red, Color.blue,
                                           Color.yellow, Color.orange,
                                           Color.black,  Color.white };
   private static final int WIDTH = 400,
                            HEIGHT = 400,
                            NUMBER_OF_CIRCLES = 1000;

   public Test() {
      Container contentPane = getContentPane();
     
      JButton button = new JButton("Draw Circle");
      final JPanel  panel  = new JPanel();

      contentPane.add(panel,  BorderLayout.CENTER);
      contentPane.add(button, BorderLayout.SOUTH);
      setSize(WIDTH ,HEIGHT);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setVisible(true);

      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent event) {
            Graphics g = panel.getGraphics();

            for(int i=0; i < NUMBER_OF_CIRCLES; ++i) {
               Circle circle = new Circle(getRandomColor());
               circle.draw(g, getRandomX(), getRandomY(), getRandomR());//1000 object created.
            }
         }
      });
   }

   private int getRandomX() {
      return (int)(Math.random()*WIDTH );
   }
   private int getRandomY() {
      return (int)(Math.random()*HEIGHT);
   }
   private int getRandomR() {
      return (int)(Math.random()*(HEIGHT/10));
   }
   private Color getRandomColor() {
      return colors[(int)(Math.random()*colors.length)];
   }
   public static void main(String[] args) {
      Test test = new Test();
   }  
}

From the above code, you may note that 1000 circle object has been created. It is memory consuming.

To improve it, we will create a CircleFactory class to customize it by using flyweight design pattern. Since we just draw circle with different colors, we can store color info in a hashmap. If a circle has been drawn, the new circle will be checked with color. If the circle with the same color has been found in the hashmap, the circle will share the instance which is picked up from the hashmap instead of creating a new one. We will reuse the object with different state, that is to say we will share the instance and draw the circle with different start position and radius on the fly.

class CircleFactory {
   //store color
   private static final HashMap circleByColor = new HashMap();

   public static Circle getCircle(Color color) {
      Circle circle = (Circle)circleByColor.get(color);

      if(circle == null) {
         circle = new Circle(color);
         circleByColor.put(color, circle);
         System.out.println("Creating " + color + " circle");//see how many objects we create on command line
      }
      return circle;
   }
}

So our test program will be coded as follows:

import java.awt.*;
import java.util.HashMap;
import java.awt.Color;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

class Test extends JFrame{
   private static final Color colors[] = { Color.red, Color.blue,
                                           Color.yellow, Color.orange,
                                           Color.black,  Color.white };
   private static final int WIDTH = 400,
                            HEIGHT = 400,
                            NUMBER_OF_CIRCLES = 1000;

   public Test() {
      Container contentPane = getContentPane();
     
      JButton button = new JButton("Draw Circle");
      final JPanel  panel  = new JPanel();

      contentPane.add(panel,  BorderLayout.CENTER);
      contentPane.add(button, BorderLayout.SOUTH);
      setSize(WIDTH,HEIGHT);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setVisible(true);

      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent event) {
            Graphics g = panel.getGraphics();
            for(int i=0; i < NUMBER_OF_CIRCLES; ++i) {
                Circle circle = CircleFactory.getCircle(getRandomColor());
                circle.draw(g, getRandomX(), getRandomY(),getRandomR());
               //Since we have 6 different colors, we have 6 objects created.
            }
          }
      });
   }
   public static void main(String[] args) {
      Test test = new Test();
   }
   private int getRandomX() {
      return (int)(Math.random()*WIDTH );
   }
   private int getRandomY() {
      return (int)(Math.random()*HEIGHT);
   }
   private int getRandomR() {
      return (int)(Math.random()*(HEIGHT/10));
   }
   private Color getRandomColor() {
      return colors[(int)(Math.random()*colors.length)];
   }
}

class CircleFactory {
   private static final HashMap circleByColor = new HashMap();

   public static Circle getCircle(Color color) {
      Circle circle = (Circle)circleByColor.get(color);

      if(circle == null) {
         circle = new Circle(color);
         circleByColor.put(color, circle);
         System.out.println("Creating " + color + " circle");
      }
      return circle;
   }
}

class Circle {
   private Color color;

   public Circle(Color color) {
      this.color = color;
   }
   public void draw(Graphics g, int x, int y, int r) {
      g.setColor(color);
      g.drawOval(x, y, r, r);
   }
}

Copy, paste above code and run it. You will see the printout from the command line, that you only have 6 objects created, not 1000 objects because you only have 6 colors. Such a big reduction of object creation will improve your program performance dramatically.

Output :
Creating java.awt.Color[r=255,g=0,b=0] circle
Creating java.awt.Color[r=0,g=0,b=0] circle
Creating java.awt.Color[r=255,g=200,b=0] circle
Creating java.awt.Color[r=255,g=255,b=0] circle
Creating java.awt.Color[r=0,g=0,b=255] circle
Creating java.awt.Color[r=255,g=255,b=255] circle

 flyweight pattern


 

Flyweight design is effective with instantiating a large amount of small and fine-grained classes by combining with factory design pattern.

If you have jdk1.5 installed, you may need to use a tool to check if you save the memory by running your commands as follows:

C:\\> java -Dcom.sun.management.jmxremote Test
And open another console as follows:

C:\\> jconsole

 The jconsole tool will hook up your program Test to give your statistic numbers about your program, such as threads, heap, memory, VM, etc.

String class is designed with Flyweight design pattern. It has similar structure as above example. When you create a string constant, such constant is stored in a pool. When the second string is created, it will be checked to see if it has been created. If it is true, the second string instance will be picked up from the string pool instead of creating a new one. This is why the following code makes sense, but bothers many people.

String s1 = "hello";
String s2 = "hello"; //store in a string pool.
String s3 = new String("hello");

System.out.println(s1==s2); //true, share the same memmory address
System.out.println(s1==s3); //false

Your Ad Here




footer for Flyweight Pattern page