Tuesday, February 28, 2006

Using Java 5 enums for the Command Pattern

Perhaps posted about elsewhere (my Google search did not turn up what I was looking for), one of the best uses for Java 5 enums is to implement the well-known Command Pattern.

Just one simple example with two commands, START and FINISH, and a simple execution parameter, sessionId:

/**
 * Demonstrates using JDK5 {@code enum}s for the Command Pattern.
 * 
 * @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a>
 */
public enum CommandEnum {
    /**
     * The {@code START} command.
     */
    START() {
        @Override
        public void execute(final SessionId sessionId) {
            System.out.println("Start: " + sessionId);
        }
    },
    /**
     * The {@code FINISH} command.
     */
    FINISH() {
        @Override
        public void execute(final SessionId sessionId) {
            System.out.println("Finish: " + sessionId);
        }
    };
    
    /**
     * Executes the command.
     */
    public abstract void execute(final SessionId sessionId);
    
    public static void main(final String[] args) {
        final SessionId mySessionId = new SessionId(13);
        
        for(final CommandEnum command : CommandEnum.values())
            command.execute(mySessionId);
        
        final SessionId yourSessionId = new SessionId(31);
        
        CommandEnum.valueOf("START").execute(yourSessionId);
        CommandEnum.valueOf("FINISH").execute(yourSessionId);
    }
    
    private static final class SessionId {
        private final int id;
        
        SessionId(final int id) {
            this.id = id;
        }
        
        @Override
        public String toString() {
            return Integer.toString(id);
        }
    }
}

A nice benefit of this use of enum is that one need not refactor existing code to take advantage. Use the enums with the Adapter or Facade Patterns and replace the bodies of execute() with forwarding calls to the original code implementations. Then new code can use the Command Pattern while existing code can continue to use the (possibly @Deprecated) original calls.

No comments: