繁体   English   中英

如何从类名称获取单例实例作为字符串

[英]How to get singleton instance from a class name as string

我遇到一个奇怪的问题。 我有一个接口,其实现往往是无状态的。 所以,我希望他们成为单身人士。

我将实现类名称作为字符串获取。 例如

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;
    }
}

如果该类没有静态的getInstance()方法,则上面的代码将引发NullPointerException 在Java 6中,我不能在接口中使用静态方法。 我不想创建IRule实现的多个实例。 如果我可以强制执行静态方法并调用该静态方法,则将获得现金实例。 但是我做不到。 如何解决这个问题呢?

有几种解决方案各有优缺点:

  1. 不要使用static方法。 如果该方法不是静态的,则可以将其添加到IRule并因此强制该方法存在。
  2. 检查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 );
    }
}

您正在使生活变得不必要。

如果您还记得很棒的“ 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单例模式”的伟大之处在于它已经保证了singleton属性,因此上面的代码没有做任何尝试检测并发查找的尝试,因为它们保证了返回相同的单个实例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM