Enum Factory Pattern

Today I came up with a cool way to use java's enums in a factory pattern. Specifically, the type of factory pattern where you want to create one of several sub-classes depending on the value of some variable.

For those of you who are not too familiar with java's crazy enumeration type the next section attempts to get the basics down. If you know all about enums already feel free to skip to the second part, where their use as subclass factories is described.

A bit about enums

Java's enum type is fairly advanced and pretty neat. It allows you to replace code like this:

public static final int LEFT_ALIGNMENT   = 0;
public static final int RIGHT_ALIGNMENT  = 1;
public static final int CENTER_ALIGNMENT = 2;
public static final int JUSTIFIED        = 3;

With code like this:

public enum Justification { LEFT, RIGHT, CENTER, JUSTIFIED }

So instead of writing int align = LEFT_ALIGNMENT you use Justification align = Justification.LEFT. The main benefits here are that you don't have to maintain a list of integers, it's semantically closer to what you were aiming for and the compiler checks if the enum exists, IE you don't have to handle the possibility of receiving an int value not in your list.

In addition you can add methods & instance fields to enums, treating them as tiny classes. It's even possible for enums to implement interfaces. The most useful way of using this functionality is as in the example below, showing the extremely useful enum Elephant:

public enum Elephant
{
    AFRICAN_BUSH ("Big & pointy", "Way Awesome"),
    AFRICAN_FOREST ("Big & rounded", "Pretty awesome"),
    ASIAN ("Small & pointy", "Log-handling Awesome");

    private Elephant(String ears, String rating)
    {
        this.ears = ears;
        this.rating = rating;
    }
   
    public final String ears;
    public final String rating;
}

In this example the enum Elephant acts like a class with a limited number of instantiations, a set of 'singletons'. By declaring Elephant billy = Elephant.ASIAN you set billy to point to one of them, and you can pass this reference around to anyone who needs it. Anyone interested in Billy's awesomeness rating can refer to billy.rating to receive "Log-handling Awesome".

The big difference with classes is that you can still use them in traditional enum ways. For example, you might construct an Elephant based movie using something like Movie movie = new ElephantMovie(Elephant.ASIAN); And unlike classes, enums can be used in switch statements and compared using the == operator.
A list of all values an enumeration can have can be obtained with the static method values(). A call to Elephant.values() will return the array { AFRICAN_BUSH, AFRICAN_FOREST, ASIAN }.

A small downside to using enum instead of a collection of public final static ints is that - unless you place your enum in a seperate file - you'll usually end up addressing a particular value of an enum type as EmbeddingClass.Elephant.ASIAN.

An enum based factory

And now for the fun part.

For a work-related project I was interested in letting a user select one of a number of random number generators from a drop-down combobox. This generator should then be used to generate some random numbers, run a simulation, etc etc.

The following enum type provides (or more precisely enables) a clean and simple way to achieve this.

public enum Distribution
{
    NORMAL ("Normal"),
    LOGNORMAL ("Lognormal"),
    GAMMA ("Gamma"),
    EXPONENTIAL ("Exponential"),
    UNIFORM ("Uniform");
   
    private Distribution(String name)
    {
        this.name = name;
    }
   
    public String toString()
    {
        return name;
    }
   
    public DistributedGenerator get()
    {
        switch(this)
        {
            case NORMAL: return new NormalGenerator();
            case LOGNORMAL: return new LognormalGenerator();
            case GAMMA: return new GammaGenerator();
            case EXPONENTIAL: return new ExponentialGenerator();
            default: return new UniformGenerator();
        }
    }
   
    private String name;
}

Compared to string-based or int-based factory methods this has the following advantages:

Another alternative would be to construct the object in a GUI class and pass the constructed object on to whoever needs it, after all, the classes all implement the same interface. With the enum factory method construction can be put off until the object is needed. This might have some overhead advantages, but the real advantage is that adding arguments to the get() method allows you to determine the type of object first, and the constructor arguments later.

GUI Advantages

The coolest feature of this model is its use in combo boxes. A JComboBox has a constructor that takes an array of Objects as its argument, and then calls each object's toString() method to create a user-friendly listing. So creating a combobox showing all types listed in the enumeration becomes as simple as JComboBox combo = new JComboBox(Distribution.values()); When the user has selected an item and clicked the "go!" button the enum can be retrieved by using combo.getSelectedItem() and casting back to the Distribution type. Finally, the requested object can then be created with the enum's get() method.

Everything the GUI knows about Distributions it gets from this enum, which allows for a clean cut between GUI and math classes. Finally, updating the enumeration automatically updates the GUI, which means that subclasses can be added or removed from the program without updating any GUI files.

Aug 22nd, 2008

Comments

anonymous wrote:

Simply a Beauty.!!! thanks blogger!

Oct 27th, 2013

Kumar wrote:

public enum Weeks
{
    MONDAY("hi"),
    TUESDAY("TUESDAY"),
    WEDNESDAY("WEDNESDAY"),
    THURSDAY("THURSDAY"),
    FRIDAY("FRIDAY"),
    SATURDAY("SATURDAY"),
    SUNDAY("SUNDAY");
   
    public static String getWeekInfo(String display1)
    {   for(Weeks w: values())
        {      
            String Week=w.name();
            System.out.println(""+Week);
            if(Week.equals(display1))
            {
                System.out.println("SS"+Week.valueOf(Week));
            }
        }
        return display1;
    }
   
    Weeks(String display)
    {
        this.display=display;
    }
   
    private String display;
    /**
     * @return the display
     */

    public String getDisplay()
    {
        return display;
    }
}

Jan 20th, 2012

jmickk wrote:

Gary, excellent suggestion above about using abstract. I'll use it!

Jul 29th, 2011

Srini wrote:

Just came across this code. Beautiful!!! Thank you!

Feb 4th, 2011

Michael wrote:

Parameters is a problem indeed! I must admit, my example here is more complicated in real life, since the exponential generator (for example) has an input argument and the gamma generator has two. My solution has been to use default parameters at initialisation and then have the GUI switch on the enum to determine if it needs to add some input fields.
It's not pretty, but I can't think of a solution that would handle this without building an extensive API...

Sep 3rd, 2009

Julen Parra wrote:

Even niftier, IMO, would be to just store the NormalGenerator.class, LognormalGenerator.class, etc, and then instantiate a new class with newInstance() or getConstructor().newInstance() if taking parameters.

Just my luck, I had to take a set of classes where some take parameters and some no. Working on it :o)

Sep 2nd, 2009

michael wrote:

/**
 * You can now use <code> tags in the comment section.
 *  By adding a class="java" or php, python, c etc, you can get syntax
 *  highlighting in your language of choice
 */

class Comment
{
  public static void main(String[] args)
  {
    System.out.println("Done!");
  }
}

May 19th, 2009

michael wrote:

Sorry bout that, still need to add some syntax highlighting :)
For now I'm taking the cowards' way out and doing it manually

I never thought of adding abstract methods, it works out great when there's multiple methods too. Thank you!

May 5th, 2009

Gary wrote:

Wow - that did not come out like I was expecting.

May 5th, 2009

Gary wrote:

Hey there. Not sure how I stumbled across this post but I wanted to make a couple of suggestions to your example that might improve usability just a bit.

1) If you override toString() you should consider writing a fromString method to convert the textual representation back to the associated enum.

2) Use abstract methods rather than a switch.
The disadvantage to using a switch is that you have to remember to
alter the code in the get() method every time you change an enum. By
using an abstract method, you are forced to implement the method at
the enum level.

Final example:public enum Distribution
{
      NORMAL("Normal") { DistributedGenerator get() { return new NormalGenerator(); } },
      LOGNORMAL("Lognormal") { DistributedGenerator get() { return new LognormalGenerator(); } },
      GAMMA("Gamma") { DistributedGenerator get() { return new GammaGenerator(); } },
      EXPONENTIAL("Exponential") { DistributedGenerator get() { return new ExponentialGenerator(); } },
      UNIFORM("Uniform") { DistributedGenerator get() { return new UniformGenerator(); } };
     
      private static final Map<String, Distribution> stringMap = new HashMap<String, Distribution>();
     
      static
      {
        for(Distribution dist : values())
            stringMap.put(dist.toString(), dist);
      }
     
      private Distribution(String name)
      {
        this.name = name;
      }
     
      @Override public String toString()
      {
        return name;
      }
     
      public static Distribution fromString(String name)
      {
        return stringMap.get(name);
      }
     
      abstract DistributedGenerator get();
     
      private String name;

}
Cheers.

May 5th, 2009

Post your comments here

If you wish to add code to your comment you can use code tags, like this: <code class="php">yourCodeHere</code>.
Quite a large number of languages are supported, although I can't guarantee it'll be pretty. Inside the code tags you can use any characters except for the string "</code>".