我遇到了一个奇怪的问题。我有一个接口,其实现往往是无状态的。所以,我希望他们成为单身人士。
我将实现类名称作为字符串。例如
String clazz = "com.foo.Bar";
我有一个规则工厂来获取IRule
实现的实例。
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;
}
}
如果类没有静态NullPointerException
方法,则上面的代码会抛出getInstance()
。在Java 6中,我不能在接口中使用静态方法。我不想创建IRule
实现的多个实例。如果我可以强制执行静态方法并调用该静态方法,我将获得兑现实例。但我无法做到这一点。如何解决这个问题?
答案 0 :(得分:1)
有几种解决方案有不同的优点和缺点:
static
方法。如果该方法不是静态的,则可以将其添加到IRule
,从而强制该方法存在。factoryMethod
的限定符,并在不是static
对于解决方案#1,您需要Map<String,IRule>
。调用getRuleInstance()
时,请检查地图以查找实例。如果没有,请使用界面中的方法创建一个并将其放入地图中。这样,您就可以将实例单例化。
同时,您可以获取实例的所有字段,并确保所有字段都final
来强制执行无状态。
如果您的应用程序是多线程的,请确保使用并发映射并正确同步。
示例代码:
private Map<String, IRule> rules = Maps.newHashMap();
public static <T extends IRule> T getRuleInstance(String clazz) {
try {
synchronized( rules ) {
IRule result = rules.get(clazz);
if(null == result) {
result = clazz.newInstance();
rules.put(clazz, result);
}
@SuppressWarnings("unchecked")
T tmp = (T) result;
return tmp;
}
} catch (Exception e) {
log( "Unable to create IRule for {}", clazz );
}
}
答案 1 :(得分:1)
你的生活变得不必要了。
如果你还记得伟大的“enum
单例模式”并要求所有实现者都使用它,例如
public enum Foo implements IRule
{
INSTANCE;
// IRule implementation methods here
public String toString() { return "the sole Foo instance"; }
}
整个RulesFactory
变得如此简单:
private static final ConcurrentMap<String, IRule> instancesMap
= new ConcurrentHashMap<String, IRule>();
public static IRule getRuleInstance(String clazz) {
try {
IRule iRuleInstance=instancesMap.get(clazz);
if(iRuleInstance!=null) return iRuleInstance;
Class<? extends IRule> ruleObject=Class.forName(clazz).asSubclass(IRule.class);
IRule[] enumConstants=ruleObject.getEnumConstants();
if(enumConstants==null || enumConstants.length!=1) {
logger.error("InvalidClassException",
new InvalidClassException(clazz, "not a singleton enum"));
return null;
}
iRuleInstance=enumConstants[0];
instancesMap.put(clazz, iRuleInstance);
return iRuleInstance;
} catch (ClassNotFoundException e) {
logger.error("ClassNotFoundException", e);
}
return null;
}
“enum
单例模式”的优点在于它已经保证了单例属性,因此上面的代码不会尝试检测并发查找,因为它们可以保证返回相同的单个实例