How to instantiate a Singleton multiple times?
I need a singleton in my code. I implemented it in Java and it works well. The re开发者_开发百科ason I did it, is to ensure that in a mulitple environment, there is only one instance of this class.
But now I want to test my Singleton object locally with a Unit test. For this reason I need to simulate another instance of this Singleton (the object that would be from another device). So is there a possiblity to instantiate a Singleton a second time for testing purpose or do I have to mock it?
I'm not sure, but I think it could be possible by using a different class loader?
Traditionally, a Singleton creates its own instance, and it creates it only once. In this case it is not possible to create a second instance.
If you use Dependency Injection, you can let the framework create the singleton for you. The singleton does not guard against other instances (i.e. it has a public constructor), but the dependency injection framework instantiates only one instance. In this case, you can create more instances for testing, and your object is not cluttered with singleton code.
The point of a Singleton is that you can only instantiate it once.
You can invoke the private constructor of your singleton class using reflection to create a new instance of the class.
class MySingleton {
private MySingleton() {
}
}
class Test {
public void test() throws Exception {
Constructor<MySingleton> constructor = MySingleton.class.getConstructor();
constructor.setAccessible(true);
MySingleton otherSingleton = constructor.newInstance();
}
}
A singleton, by definition, can only be instantiated once. However, the fact that your unit test requires two singletons is a strong indication that your object shouldn't really be a singleton, and that you should rethink the singleton design.
I feel compelled to post this series of articles about how Singletons destroy testability and are poor design choices:
- Singletons are Pathological Liars
- Where Have All the Singletons Gone?
- Root Cause of Singletons
Short summary: combining logic for what a class does with how it is instantiated makes code that is ugly to test, and should be avoided.
First, why do you need to create a new singleton to run a unit test? A unit test should not be running concurrently with the normal application, so you should be able to access the original singleton without fear of modifying it..
Is there a particular reason you need an explicit second singleton?
you could just make another static method getInstance2
that looks like this:
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();
will return singleton object. By making use of "ston" object, if we call the method createNewSingleTonInstance()
which is written in Singleton class will give new instance.
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;
}
}
You may keep a key on a map and populate instance with key
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;
}
}
精彩评论