【问题标题】:How to instantiate a Singleton multiple times?如何多次实例化单例?
【发布时间】:2010-06-17 18:53:37
【问题描述】:

我的代码中需要一个单例。我用 Java 实现了它,它运行良好。我这样做的原因是为了确保在多个环境中,只有一个此类的实例。

但现在我想用单元测试在本地测试我的 Singleton 对象。出于这个原因,我需要模拟这个 Singleton 的另一个实例(来自另一个设备的对象)。那么是否有可能第二次实例化一个 Singleton 以用于测试目的,还是我必须模拟它?

我不确定,但我认为可以通过使用不同的类加载器来实现?

【问题讨论】:

  • 嗯.. 名称排序表明必须只有一个实例。如果不能这样测试,我建议类的设计可能存在缺陷。
  • 两次实例化单例不会是测试失败吗?对于单身人士来说,这是一个定义明确的错误行为......
  • 这是应该像瘟疫一样避免单身人士的众多原因之一。
  • sry 不小心回滚了
  • 究竟为什么您的测试需要实例化第二个单例?

标签: java singleton


【解决方案1】:

传统上,Singleton 创建自己的实例,并且只创建一次。在这种情况下,无法创建第二个实例。

如果你使用依赖注入,你可以让框架为你创建单例。单例不防范其他实例(即它有一个公共构造函数),但依赖注入框架只实例化一个实例。在这种情况下,您可以创建更多实例进行测试,并且您的对象不会被单例代码弄得乱七八糟。

【讨论】:

    【解决方案2】:

    Singleton 的关键在于你只能实例化一次。

    【讨论】:

    • 是的,这就是我使用它的原因。但我认为有办法做到这一点。
    • @Sebi - 然后用它测试。或者在没有它的情况下使用模拟进行测试,但不要试图让它不是它。
    【解决方案3】:

    您可以使用反射调用单例类的私有构造函数来创建该类的新实例。

    class MySingleton {
        private MySingleton() {
        }
    }
    
    class Test {
        public void test() throws Exception {
            Constructor<MySingleton> constructor = MySingleton.class.getConstructor();
            constructor.setAccessible(true);
            MySingleton otherSingleton = constructor.newInstance();
        }
    }
    

    【讨论】:

    • 当然,或者您可以只继承 MySingleton 以公开构造函数。如果您有调用 MySingleton.getInstance().blach() 的现有代码,那么所有这些代码都会失败。
    • 这是为了测试单例类。我不建议在非测试代码中这样做。我认为可以使用反射来达到其他无法达到的方法以进行测试。
    • 我认为只修复代码而不是用反射来破解它要好得多。
    • 为什么我用 java6 得到“java.lang.NoSuchMethodException”?这个有补丁吗?
    【解决方案4】:

    根据定义,单例只能实例化一次。但是,您的单元测试需要 两个 单例这一事实强烈表明您的对象不应该真的是单例,并且您应该重新考虑单例设计。

    【讨论】:

    • 或者,反过来说,测试本身是谨慎的。
    • 在这种情况下,创建 resetInstance 方法来删​​除类中的私有实例可能会有所帮助 - 这将有助于测试这种情况
    【解决方案5】:

    我觉得有必要发布这一系列关于单例如何破坏可测试性并且是糟糕的设计选择的文章:

    简短的总结:将类的功能与实例化方式的逻辑结合起来会使代码难以测试,应该避免。

    【讨论】:

      【解决方案6】:

      首先,为什么需要创建一个新的单例来运行单元测试?单元测试不应与普通应用程序同时运行,因此您应该能够访问原始单例而不用担心对其进行修改..

      您需要明确的第二个单例是否有特殊原因?

      【讨论】:

        【解决方案7】:

        您可以创建另一个静态方法getInstance2,如下所示:

        class MySingleton
        {
            private MySingleton(){}
            private static MySingleton instance1 = new MySingleton();
            private static MySingleton instance2 = new MySingleton();
        
            public static MySingleton getInstance(){ return instance1; }
            public static MySingleton getInstance2(){ return instance2; }
        }
        

        【讨论】:

        • 嗯是的,但是我必须更改代码。如果可能的话,我想避免这种情况。
        • 猜猜这是破坏代码的好方法。从好的方面来说,你以后的单元测试会更频繁地触发异常:-)
        【解决方案8】:

        Singleton ston=Singleton.getInstance(); 将返回单例对象。通过使用“ston”对象,如果我们调用在 Singleton 类中编写的方法createNewSingleTonInstance() 将给出新的实例。

        public class Singleton {
        
        private String userName;
        private String Password;
        private static Singleton firstInstance=null;
        private Singleton(){}
        
        
        public static synchronized Singleton getInstance(){
            if(firstInstance==null){
                firstInstance=new Singleton();
                firstInstance.setUserName("Prathap");
                firstInstance.setPassword("Mandya");
            }
            return firstInstance;
        }
        
        
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public String getUserName() {
            return userName;
        }
        public void setPassword(String password) {
            Password = password;
        }
        public String getPassword() {
            return Password;
        }
        
        public Singleton createNewSingleTonInstance(){
            Singleton s=new Singleton();
            s.setUserName("ASDF");
            s.setPassword("QWER");
            return s;
        }
        }
        

        【讨论】:

          【解决方案9】:

          您可以在地图上保留一个键并使用键填充实例

          public class MultiSingleton {
          /**** Non-static Global Variables ***/
          String status = "";
          private BaseSmartCard bsc;
          /***********************************/
          private static Object lockObject = new Object();
          private String serialNo;
          
          private static Map<String, MultiSingleton> mappedObjects = new TreeMap<String, MultiSingleton>();
          
          protected MultiSingleton() {
          
          }
          
          
          public static MultiSingleton getInstance(String serialNo,long slotNo){
              if (mappedObjects.isEmpty() || !mappedObjects.containsKey(serialNo)) {
                  MultiSingleton instance = new MultiSingleton();
                  instance.setSerialNo(serialNo);
                  mappedObjects.put(serialNo, instance);
                  return instance;
              } else if (mappedObjects.containsKey(serialNo)) {
                  return mappedObjects.get(serialNo);
              }else {
                  return null;
              }
          }
          

          【讨论】:

            猜你喜欢
            • 2021-04-04
            • 2023-04-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-10
            相关资源
            最近更新 更多