Java 如何多次实例化一个单例?
我的代码中需要一个单例。我用Java实现了它,效果很好。我这样做的原因是为了确保在多个环境中,这个类只有一个实例 但是现在我想用单元测试在本地测试我的单例对象。出于这个原因,我需要模拟这个单例的另一个实例(来自另一个设备的对象)。那么,是否有可能为了测试目的再次实例化一个单例,或者我必须模拟它Java 如何多次实例化一个单例?,java,singleton,Java,Singleton,我的代码中需要一个单例。我用Java实现了它,效果很好。我这样做的原因是为了确保在多个环境中,这个类只有一个实例 但是现在我想用单元测试在本地测试我的单例对象。出于这个原因,我需要模拟这个单例的另一个实例(来自另一个设备的对象)。那么,是否有可能为了测试目的再次实例化一个单例,或者我必须模拟它 我不确定,但我认为使用不同的类加载器是可能的?单例的要点是您只能实例化它一次。您可以创建另一个静态方法getInstance2,如下所示: class MySingleton { private
我不确定,但我认为使用不同的类加载器是可能的?单例的要点是您只能实例化它一次。您可以创建另一个静态方法
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不防范其他实例(即它有一个公共构造函数),但依赖注入框架只实例化一个实例。在这种情况下,您可以创建更多的实例进行测试,并且您的对象不会被单例代码弄乱。根据定义,单例只能实例化一次。然而,单元测试需要两个单例,这一事实强烈表明,您的对象不应该是真正的单例,您应该重新考虑单例设计。您可以使用反射调用单例类的私有构造函数来创建该类的新实例
class MySingleton {
private MySingleton() {
}
}
class Test {
public void test() throws Exception {
Constructor<MySingleton> constructor = MySingleton.class.getConstructor();
constructor.setAccessible(true);
MySingleton otherSingleton = constructor.newInstance();
}
}
classmysingleton{
二等兵迈辛格尔顿(){
}
}
课堂测试{
public void test()引发异常{
构造函数=MySingleton.class.getConstructor();
constructor.setAccessible(true);
MySingleton otherSingleton=constructor.newInstance();
}
}
我觉得有必要发布这一系列关于单例如何破坏可测试性和糟糕的设计选择的文章:
简短总结:将类的功能逻辑与实例化方式结合起来,会使代码难以测试,应该避免这种情况。首先,为什么需要创建新的单例来运行单元测试?单元测试不应与普通应用程序同时运行,因此您应该能够访问原始单例,而无需担心修改它
您需要显式的第二个单例有什么特别的原因吗?
singleton ston=singleton.getInstance()代码>将返回单例对象。通过使用“ston”对象,如果调用在Singleton类中编写的方法CreateNewsingleToInstance()
,将给出新的实例
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<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;
}
}
public-class-MultiSingleton{
/****非静态全局变量***/
字符串状态=”;
私人智能卡bsc;
/***********************************/
私有静态对象lockObject=新对象();
私有字符串序列号;
私有静态映射mappedObjects=新树映射();
受保护的MultiSingleton(){
}
公共静态MultiSingleton getInstance(字符串serialNo,long slotNo){
if(mappedObjects.isEmpty()| |!mappedObjects.containsKey(serialNo)){
MultiSingleton实例=新的MultiSingleton();
实例.setSerialNo(serialNo);
put(serialNo,instance);
返回实例;
}else if(mappedObjects.containsKey(serialNo)){
返回mappedObjects.get(serialNo);
}否则{
返回null;
}
}
Um..名称排序表明必须只有一个实例。如果无法对其进行测试,我建议类的设计中可能存在缺陷。两次实例化一个单例不是测试失败吗?这是单例定义明确的错误行为…这是应避免单例的许多原因之一ike the peast.sry意外回滚确切地说,为什么您的测试需要实例化第二个单例?嗯,是的,但是我必须更改代码。如果可能的话,我想避免这种情况。我想这是破坏代码的好方法。从好的方面来说,您以后的单元测试将更频繁地触发异常:-)是的,这就是我使用它的原因。但是我认为人们可以通过某种方式做到这一点。@Sebi-然后使用它进行测试。或者使用一个mock进行测试,但不要试图让它成为不可能的东西。当然,或者您可以将MySingleton子类化以公开构造函数。如果您有调用MySingleton.getInstance().blach()的现有代码,所有这些代码都会失败。这是为了测试一个单例类。我不建议在非测试代码中这样做。我认为使用反射来达到其他无法达到的方法来进行测试是可以的。我认为修复代码比使用反射来绕过代码要好得多。为什么我会java6中的“java.lang.NoSuchMethodException”?这是否已修补?或者相反,测试本身是谨慎的。在这种情况下,创建删除类内私有实例的resetInstance
方法可能会有所帮助-这将有助于测试此类情况