Bo's blog

Saturday, November 14, 2009

Java enum

Enums and Template Methods

Remember that the enum is basically a special class type, and can have methods and fields just like any other class. Remember also that each declared field is also an instance of the enum. So, applying the "Template Method" design pattern, one can create enumerations that are factories or command objects, but a defined set of objects. Here is a simple example of a "command" enumeration:

public enum Toy {
DOLL() {
@Override public void execute() {
System.out.println("I'm a doll.");
}
},
SOLDIER() {
@Override public void execute() {
System.out.println("I'm a soldier.");
}
};
//template method
public abstract void execute();
}


Another solution to seperate the implementation.


enum ToyEnum implements Toy
{
  DOLL(new Doll ()), SOLDIER(new Soldier ());
  final private Toy impl;
  private ToyEnum (Toy impl)
  {
    this.impl = impl;
  }
  //template method
  public void execute ()
  {
    impl.execute ();
  }
}
interface Toy
{
  public void execute ();
}
class Doll implements Toy
{
  public void execute ()
  {
    System.out.println ("I'm a doll.");
  }
}
class Soldier implements Toy
{
  public void execute ()
  {
    System.out.println ("I'm a soldier.");
  }
}


With the use of static imports, the client code calling this enumeration would look like:



SOLDIER.execute();
DOLL.execute();
//or better...
getToy().execute();


The resulting code is clear and self-documenting. Using this pattern is a great alternative in many cases to the more common if(toy=="soldier"){...} else if(toy=="doll"){...} else{...} logic since it is easier to read, extend, and maintain.



 



Reverse Lookups



Often in your object model it is common to have data that is naturally "associated" with an enumeration. Since an enum is a class, it is easy to represent this associated information as class fields. Often it is desirable to "lookup" the associated enumeration using the field value. This is easy to do using a static java.util.Map. Take, for example, a Status enum that has an associated status code.



public enum Status 
{
WAITING(0),
READY(1),
SKIPPED(-1),
COMPLETED(5);

private static final Map<Integer,Status> lookup
= new HashMap<Integer,Status>();

static {
for(Status s : EnumSet.allOf(Status.class))
lookup.put(s.getCode(), s);
}

private int code;

private Status(int code) {
this.code = code;
}

public int getCode() { return code; }

public static Status get(int code) {
return lookup.get(code);
}
}


The static get(int) method here provides the reverse lookup by simply getting the value from the Map. The static block to populate the Map uses a specialized implementation of Set, java.util.EnumSet, that "probably" (according to the javadocs) has better performance than java.util.HashSet. Java 5.0 also provides java.util.EnumMap, a specialized implementation of Map for enumerations that is more compact than java.util.HashMap.

0 Comments:

Post a Comment

<< Home