2010-06-17 18 views
7

Necesito un singleton en mi código. Lo implementé en Java y funciona bien. La razón por la que lo hice es asegurar que en un entorno múltiple, solo haya una instancia de esta clase.¿Cómo crear una instancia de Singleton varias veces?

Pero ahora quiero probar mi objeto Singleton localmente con una prueba de unidad. Por esta razón, necesito simular otra instancia de este Singleton (el objeto que sería de otro dispositivo). Entonces, ¿hay una posibilidad de instanciar un Singleton por segunda vez para fines de prueba o tengo que burlarlo?

No estoy seguro, pero creo que podría ser posible utilizando un cargador de clases diferente?

+4

Um .. el nombre de tipo de indica que debe haber sólo una única instancia. Si no se puede probar como tal, sugiero que puede haber un defecto en el diseño de la clase. –

+6

¿No sería una falla de prueba crear instancias de Singleton dos veces? Este es un comportamiento incorrecto bien definido para un singleton ... – Piskvor

+1

Esta es una de las muchas razones por las cuales los Singleton deben evitarse como la peste. – ColinD

Respuesta

9

Puede invocar el constructor privado de su clase singleton utilizando la reflexión para crear una nueva instancia de la clase.

class MySingleton { 
    private MySingleton() { 
    } 
} 

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

Claro, o podría simplemente subclase MySingleton para exponer el constructor. Si tiene un código existente que invoca MySingleton.getInstance(). Blach(), todo este código fallará. – Justin

+0

gracias eso es lo que estoy buscando – RoflcoptrException

+0

Esto es con el propósito de probar una clase singleton. No recomiendo hacer esto en un código que no sea de prueba. Creo que está bien usar la reflexión para llegar a métodos que de otra manera serían inalcanzables para el propósito de las pruebas. –

16

El objetivo de Singleton es que solo puede crear una instancia una vez.

+0

sí, es por eso que lo usé. Pero pensé que de alguna manera uno puede hacerlo. – RoflcoptrException

+3

@Sebi - luego prueba con él. O usa un simulacro para probar sin él, pero no intentes convertirlo en algo que no sea. – Oded

+0

¿Por qué el voto a favor? – Oded

1

Se podía hacer otro método estático getInstance2 que tiene este aspecto:

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

hmm sí, pero entonces tendría que cambiar el código. Si es posible, quiero evitar esto. – RoflcoptrException

+0

Supongo que esta es una buena manera de destruir su código. En el lado positivo, las pruebas unitarias posteriores dispararán las excepciones mucho más a menudo :-) – Eiko

17

Tradicionalmente, un Singleton crea su propia instancia, y se crea una sola vez. En este caso, no es posible crear una segunda instancia.

Si usa Dependency Injection, puede dejar que el framework cree el singleton para usted. El singleton no protege frente a otras instancias (es decir, tiene un constructor público), pero el marco de inyección de dependencias solo instancia una instancia. En este caso, puede crear más instancias para las pruebas, y su objeto no está desordenado con el código singleton.

6

Un singleton, por definición, solo se puede crear una instancia una vez. Sin embargo, el hecho de que su unidad de prueba requiera dos singletons es una fuerte indicación de que su objeto no debería ser realmente un singleton, y que debe reconsiderar el diseño singleton.

+0

O, por el contrario, que la prueba en sí es circunspecta. – NotMe

+0

En tal caso, podría ser útil crear el método 'resetInstance' que elimina la instancia privada dentro de la clase; esto ayudará a probar tales casos – kirugan

2

Primero, ¿por qué necesita crear un singleton nuevo para ejecutar una prueba unitaria? Una prueba de unidad no debería ejecutarse al mismo tiempo que la aplicación normal, por lo que debería poder acceder al singleton original sin temor a modificarlo ..

¿Hay alguna razón en particular por la que necesite un segundo singleton explícito?

0

Singleton ston=Singleton.getInstance(); devolverá el objeto singleton. Al hacer uso del objeto "ston", si llamamos al método createNewSingleTonInstance() que está escrito en clase Singleton dará una nueva instancia.

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

Usted puede mantener una tecla en un mapa y poblar ejemplo con llave

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