Back to Design Patterns Study Group page

An Example of the Factory Method (p 107)

Intent

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

An example from Sun's Java Development Kit (JDK beta)

The general purpose abstract class, Component, provides a good deal of functionality including the ability to repaint a component (an Applet is a component), set or get Font styles, post or handle events, show or hide the component, etc. The Component class defines a Factory Method called createImage which creates new objects of the class Image. Applets (like the example below) often use this method to implement double-buffering.

Source code - Using the Component's createImage factory method

import java.awt.Graphics;
import java.awt.*;

public class Animator2 extends java.applet.Applet implements Runnable
{
  final int MAX_IMAGES = 9;
  Thread animThread = null;
  Image frame[] = new Image[MAX_IMAGES];
  Image offScrImg;
  Graphics offScrGraphics;
  boolean imagesLoaded = false;
  final int PauseSeconds = 380;
  int frame_number;

  public String getAppletInfo()
  { return "Animator2 by Joshua Kerievsky"; }

  public void init()
  {
    try
    {
      //////////// call to Factory Method //////////////
      /////////////////  createImage ///////////////////
      offScrImg = createImage(size().width, size().height);
      offScrGraphics = offScrImg.getGraphics();
    } catch (Exception e)
       offScrGraphics = null;
  }

  public void start()
  {
    if (animThread == null)
    {
      animThread = new Thread(this);
      animThread.start();
    }
  }

  public void stop()
  {
    if (animThread != null && animThread.isAlive())
      animThread.stop();
    animThread = null;
  }

  void pause(int time)
  {
    try { Thread.sleep(time); }
    catch (InterruptedException e) {}
  }

  private void loadImages()
  {
    getAppletContext().showStatus("Loading up animation images...");
    // load up all images (but last) using a MediaTracker
    MediaTracker trk = new MediaTracker(this);
    for (int i=0; i < MAX_IMAGES-1; i++)
    {
      frame[i] = getImage(getCodeBase(), i+".gif");
      trk.addImage(frame[i], i+1);
      try { trk.waitForID(i+1); } // wait for complete image to be loaded
      catch (Exception e)
        frame[i] = null;
    }
    imagesLoaded = true;
    getAppletContext().showStatus("All images loaded.");
  }

  public void run()
  {
    frame_number = MAX_IMAGES - 1;  // start with last
    while (true)
    {
      if ( !imagesLoaded )
       loadImages();
      repaint();
      pause(PauseSeconds);
      frame_number++;
      if (frame_number == MAX_IMAGES) frame_number = 0;
    }
  }

  public void update(Graphics g)
  { paint(g); }

  public void paint(Graphics g)
  {
    if (offScrGraphics != null)
    {
      offScrGraphics.drawImage(frame[frame_number], 0, 0, this);
      g.drawImage(offScrImg,0,0,this);
    }
    else
      g.drawImage(frame[frame_number],0,0,this);
  }
}

Output using Example Program

This Java applet implements double-buffering by making a call to a Factory Method which returns an Image object.



Commentary on the Factory Method