I am running into a strange problem. I have an interface, whose implementations tend to be stateless. So, I want them to be singletons.
I get the implementation class names as strings. For example
String clazz = "com.foo.Bar";
I have a rules factory to obtain instances of IRule
implementations.
public class RulesFactory {
private static final Logger logger = LoggerFactory.getLogger(RulesFactory.class);
@SuppressWarnings("unchecked")
public static <T extends IRule> T getRuleInstance(String clazz) {
try {
Class<?> ruleObject = Class.forName(clazz);
Method factoryMethod = ruleObject.getMethod("getInstance");
return (T) factoryMethod.invoke(null);
} catch (ClassNotFoundException e) {
logger.error("ClassNotFoundException", e);
} catch (IllegalAccessException e) {
logger.error("IllegalAccessException", e);
} catch (SecurityException e) {
logger.error("SecurityException", e);
} catch (NoSuchMethodException e) {
logger.error("NoSuchMethodException", e);
} catch (IllegalArgumentException e) {
logger.error("IllegalArgumentException", e);
} catch (InvocationTargetException e) {
logger.error("InvocationTargetException", e);
}
return null;
}
}
The above code throws NullPointerException
if the class doesn't have a static getInstance()
method. In Java 6 i can't use static methods in interfaces. I don't want to create multiple instances of IRule
implementations. If I can enforce a static method and invoke that static method I will get the cashed instance. But I am unable to do this. How to solve this problem?
There are several solutions with different pros and cons:
static
methods. If the method isn't static, you can add it toIRule
and therefore enforce that the method exists.factoryMethod
and throw a descriptive exception when they aren'tstatic
For solution #1, you need a
Map<String,IRule>
. WhengetRuleInstance()
is called, check the map for an instance. If there is none, use the method from the interface to create one and put it into the map. This way, you can make the instances singletons.At the same time, you can get all fields of the instance and make sure all of them are
final
to enforce the statelessness.If your application is multi-threaded, make sure you use a concurrent map and synchronize properly.
Example code:
You are making your life unnecessary hard.
If you remember the great “
enum
singleton pattern” and require that all implementors use it, e.g.the entire
RulesFactory
becomes as simple as:The great thing about the “
enum
singleton pattern” is that it already guarantees the singleton property, thus the code above doesn’t make any attempt to detect concurrent lookups as they are guaranteed to return the same single instance.