如何多次实例化Singleton?

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

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

我不确定,但我认为可以使用不同的类加载器吗?

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

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

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

如果使用dependency injection,则可以让框架为您创建单例。 单例不会防止其他实例(即它有一个公共构造函数),但dependency injection框架只实例化一个实例。 在这种情况下,您可以创建更多用于测试的实例,并且您的对象不会被单例代码混乱。

Singleton的观点是你只能实例化一次。

根据定义,单例只能实例化一次。 但是,你的unit testing需要两个单例的事实强烈表明你的对象不应该是一个单独的 ,并且你应该重新考虑单例设计。

我觉得有必要发布一系列关于Singletons如何破坏可测性并且设计选择不佳的文章:

  • 单身人士是病态的骗子
  • 所有单身人士都去了哪里?
  • 单身人士的根本原因

简短摘要:将类的逻辑与实例化方式相结合,使得代码难以测试,应该避免。

首先,为什么需要创建一个新的单例来运行unit testing? unit testing不应与正常应用程序同时运行,因此您应该能够访问原始单例而无需担心修改它。

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

你可以创建另一个静态方法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; } } 

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

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

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

 public class MultiSingleton { /**** Non-static Global Variables ***/ String status = ""; private BaseSmartCard bsc; /***********************************/ private static Object lockObject = new Object(); private String serialNo; private static Map mappedObjects = new TreeMap(); 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; } }