Java 如何从类名中获取作为字符串的单例实例
我遇到了一个奇怪的问题。我有一个接口,它的实现往往是无状态的。所以,我希望他们是单身 我将实现类名作为字符串。比如说Java 如何从类名中获取作为字符串的单例实例,java,design-patterns,reflection,singleton,Java,Design Patterns,Reflection,Singleton,我遇到了一个奇怪的问题。我有一个接口,它的实现往往是无状态的。所以,我希望他们是单身 我将实现类名作为字符串。比如说 String clazz = "com.foo.Bar"; 我有一个规则工厂来获取IRule实现的实例 public class RulesFactory { private static final Logger logger = LoggerFactory.getLogger(RulesFactory.class); @SuppressWarnings(
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;
}
}
公共类规则工厂{
私有静态最终记录器Logger=LoggerFactory.getLogger(RulesFactory.class);
@抑制警告(“未选中”)
公共静态T getRuleInstance(字符串clazz){
试一试{
Class ruleObject=Class.forName(clazz);
方法factoryMethod=ruleObject.getMethod(“getInstance”);
return(T)factoryMethod.invoke(null);
}catch(classnotfounde异常){
logger.error(“ClassNotFoundException”,e);
}捕获(非法访问例外e){
记录器错误(“IllegalacessException”,e);
}捕获(安全异常e){
logger.error(“SecurityException”,e);
}捕获(无此方法例外){
logger.error(“NoSuchMethodException”,e);
}捕获(IllegalArgumentException e){
logger.error(“IllegalArgumentException”,e);
}捕获(调用TargetException e){
logger.error(“InvocationTargetException”,e);
}
返回null;
}
}
如果类没有静态的
getInstance()
方法,上述代码将抛出NullPointerException
。在Java6中,我不能在接口中使用静态方法。我不想创建多个IRule
实现实例。如果我可以强制执行一个静态方法并调用该静态方法,我将获得已兑现的实例。但我无法做到这一点。如何解决这个问题?有几种不同利弊的解决方案:
静态方法。如果该方法不是静态的,则可以将其添加到IRule
,从而强制该方法存在
factoryMethod
的限定符,如果它们不是static
映射
。调用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 );
}
}
private Map rules=Maps.newHashMap();
公共静态T getRuleInstance(字符串clazz){
试一试{
已同步(规则){
IRule result=rules.get(clazz);
if(null==结果){
结果=clazz.newInstance();
规则。放置(clazz,result);
}
@抑制警告(“未选中”)
T tmp=(T)结果;
返回tmp;
}
}捕获(例外e){
日志(“无法为{}创建IRule”,clazz);
}
}
你让你的生活变得不必要的艰难
如果您还记得伟大的“enum
singleton模式”,并要求所有实现者都使用它,例如
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;
}
私有静态最终ConcurrentMap实例映射
=新的ConcurrentHashMap();
公共静态IRule getRuleInstance(字符串clazz){
试一试{
IRule iRuleInstance=instancesMap.get(clazz);
如果(iRuleInstance!=null)返回iRuleInstance;
CLASS另一个想法:让构造函数包的实现受到保护。让它们与RulesFactory位于同一个包中,然后基于clazz创建“new”实现并按类名将其存储在映射中。在创建新实例之前,请始终检查映射。如果方法是静态的,则Null是要传递以调用的有效值。因此,请检查getInstance()
methods.@Kayaman是的。它是有效的。但是如何强制客户机实现getInstance,以及如何将其作为静态方法来实现呢?请使用文档和良好的编程实践来强制执行它。@BRS看到您对Kayaman的回复,我觉得您应该编辑您的问题,将其作为您的关注点,而不是NPE。我认为,它已经变成了一个“鸡和e”选择一的问题。除非我有一个实例,否则我不能调用invoke方法,然后调用getInstance()就没有意义了.关于如何解决这个问题有什么想法吗?实际上我正在尝试使用Bill Pugh模式实例化实现。因此,创建两个实例会带来麻烦。一个用于调用invoke,另一个通过调用getInstance()。对于#1,调用ruleObject.newInstance()
。实际上,您应该将ruleObject
重命名为ruleType
。但是,我没有正确使用该接口吗?:有解决方案吗?有两种解决方案:1.您可以使用一个新的接口IRuleFactory
,它创建IRule
的实例。这样,您可以混合使用有状态和无状态规则(工厂可以返回相同的实例,也可以创建新实例)。2.不调用getInstance()
,而是在getRuleInstance()
中创建实例并将其放入映射中。