Applying Design Patterns with Java Enums

Over the weekend I was reading about Enum – a Java 5 feature which we normally use to define a set of constants like Month

public enum Month {

    JANUARY(1), FEBRUARY(2), MARCH(3), APRIL(4), MAY(5), JUNE(6), JULY(7), AUGUST(8), SEPTEMBER(9),OCTOBER(10),NOVEMBER(11),DECEMBER(12);

    private int monthIndex;

    private Month(int monthIndex) {
        this.monthIndex = monthIndex;
    }

    public int getMonthIndex() {
        return this.monthIndex;
    }
}

While reading about enums I was thinking that when enums have all the capabilities to be like a class then why we only use enums for defining constants. Most of the time we don’t even add any new method to the enum and we just use the default methods provided in an enum. Enum have default methods like name(),ordinal(), valueOf() etc because every enum extends a class called java.lang.Enum which has these methods.

In this blog, I will discuss how different design patterns can be used with enum.

Using enum for implementing Singleton – A Singleton ensures that a class has only one instance, and provide global point of access to it. Normally we create a singleton by making the constructor private and then exposing the instance either through static final member or exposing it through a static method like getInstance(). I will take an example of factory like SessionFactory because factories are mostly implemented as Singleton because an application typically needs one instance of a SessionFactory.

public class SessionFactory {

    public static final SessionFactory SESSION_FACTORY = new SessionFactory();

    private SessionFactory() {

    }

    public void doSomething() {
        System.out.println("I am doing something");
    }

}
  
public class SessionFactory {

    private static final SessionFactory SESSION_FACTORY = new SessionFactory();

    private SessionFactory() {

    }

    public static SessionFactory getInstance(){
        return SESSION_FACTORY;
    }

    public void doSomething() {
        System.out.println("I am doing something");
    }

}

The above two approaches to create singleton can broke if your SessionFactory class is Serializable, as it is not sufficient merely to add implements Serializable to its declaration. Each time a serialized instance is deserialized, a new instance of SessionFactory will be created. In order to avoid this, you should declare all instance fields transient and provide a readResolve method (readResolve method allows a class to replace/resolve the object read from the stream before it is returned to the caller ) .

private Object readResolve() {
        return SESSION_FACTORY;
    }

From Java 5 onwards, there is a new approach for implementing Singleton i.e. using enums.

public enum SessionFactory {

    SESSION_FACTORY;

    public void doSomething() {
        System.out.println("I am doing something");
    }
}

Using this approach, you don’t have to worry about serialization problems as enums (are serializable by default) handles it for you. This approach is more cleaner and is considered to be the best way to implement a singleton. Use this approach next time you need to implement a singleton.

Using enums for strategies : The Gang of Four definition of Strategy pattern is ” Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it”. Suppose, we are adding Validation logic in our application and you have different validation rules which can be applied. So, we can have one interface called ValidationRule interface (which defines different validation rules or strategies)

interface ValidationRule {
   void validate(input,result);
}

and then we define two validation rule strategies called Rule1 and Rule 2 which implements ValidationRule interface.

class Rule1 implements ValidationRule{
   public void validate(input,result){
    [business logic here .....];
   }
}

class Rule2 implements ValidationRule{
   public void validate(input,result){
     [business logic here .....];
   }
}

Then we inject a list of ValidationRule strategies into a Validator class using spring dependency injection.

class Validator {
ValidationResult result;
List<ValidationRule> rules;

    public void setRules(List<ValidationRule> rules){
     this.rules=rules;
    }
    public ValidationResult validate(input){
       for(ValidationRule rule:rules){
         rule.validate(input,this.result);
    }
 }
}

<bean id="validator">
 <property name="rules">
   <list>
     <bean class="com.shekhar.business.rules.Rule1"/>
     <bean class="com.shekhar.business.rules.Rule2"/>
   </list>
 </property>
</bean>

This was one way of using strategies with normal Java classes and interfaces.

In the second approach, Instead of making Rule1 and Rule2 as classes we can make them as enums.

enum Rule1 implements ValidationRule {

    Rule1;

    public void validate(input,result) {
      // business logic
    }
}

enum Rule2 implements ValidationRule {

    Rule2;

    public void validate(input,result) {
      // business logic
    }
}

You can also inject the enums using spring like this.

<bean name="validator" class="test.Validator">
		<property name="rules">
			<list>
				<ref bean="rule1"/>
				<ref bean="rule2"/>
			</list>
		</property>
	</bean>

	<bean id="rule1" class="test.Rule1" factory-method="valueOf">
		<constructor-arg>
			<value>RULE1</value>
		</constructor-arg>
	</bean>

	<bean id="rule2" class="test.Rule2" factory-method="valueOf">
		<constructor-arg>
			<value>RULE2</value>
		</constructor-arg>
	</bean>

The enum bean created by spring will always be a singleton whether you define a bean as singleton or prototype because enums are singleton.
The enum strategies approach can have advantage over the class strategies approach if you want to persist the strategies into the database using an ORM like hibernate that has support for java enum.

Using enum with template methods : The enum Rule1 and Rule2 can be moved to a single enum called ValidationRules which will define a template method called validate which all the defined set of instance will implement.

public enum ValidationRules {

    RULE1(){
      @Override
        public void validate() {

        }
    },
    RULE2(){
      @Override
        public void validate() {

        }
    };

    // template method
    public abstract void validate();

}

As you can see we have defined a template method called validate and both the instances RULE1 and RULE2 are providing an implementation of this method.