Pregunta

Estoy implementando un marco de notificación para uno de mis proyectos. Como quiero que sea muy genérico, el usuario puede usar varias capas de transporte, por lo que realmente no necesita preocuparse por usar un método de entrega (digamos WCF) u otro (por ejemplo, ActiveMQ). La interfaz que el usuario tiene acceso es, por supuesto, independiente del método de entrega (WCF o ActiveMQ). Aún así, las dos clases (consumidor y productor) implementan singletons, por lo que en realidad usan constructores predeterminados (lo que significa, sin parámetros). Mi problema es que me gustaría tener un parámetro, el método de entrega que el usuario desea usar. Pero hasta donde yo sé, Singleton solo usa constructores predeterminados? Lo cual es normal, ya que no debe haber ningún punto de usar singletons con parámetros. Entonces, ¿cuáles son mis opciones aquí? ¿No para crear un singleton? crear un método para establecer el método de entrega?

Muchas gracias por su ayuda,

Sebastián

¿Fue útil?

Solución

Ciertamente, puede tener parámetros con singletons, excepto que en lugar de pasar el parámetro a un constructor, lo está pasando al método getInstance (). Su constructor anulado debe ser privado, por supuesto, para una verdadera implementación de singleton. Mi ejemplo está escrito en Java pero también se aplica para C#.

Ejemplo:

Singleton s = Singleton.getInstance(42);

En el código singleton:

private Singleton() {

}

private Singleton(int num) {
   //set num
}

public getInstance(int num) {
  //singleton code (calls the private non-default constructor if an object 
  //does not already exist) 
}

Otros consejos

Hay algunos marcos de inyección de dependencia como Spring.net que podrían ayudarlo. Puede pasar efectivamente un parámetro en un archivo de configuración para su constructor de singletons.

Enlace a un ejemplo de marco de primavera

¿Puedo sugerir que si tiene dos comportamientos diferentes requeridos de su singleton, es posible que desee subclase? De esa manera obtienes el comportamiento que quieres llamando al singleton del comportamiento de la clase que quieres.

Puede hacerlo fácilmente con un marco de inyección de dependencia. Tengo una construcción similar en mi proyecto actual usando Mef. Todo lo que se requiere es usar las opciones de inyección del constructor, y agregar ese ensamblaje y el ensamblaje de la dependencia solicitada al catálogo, y lo alma correctamente.

Otra opción es tener alguna forma de función inicializar que tome su opción y construya la instancia de Singleton. En lugar de construirlo en el primer acceso, puede construirlo durante la llamada de inicialización. La desventaja aquí es que debe asegurarse de inicializar su singleton antes de usarlo (generalmente en el inicio del programa, usando un archivo de configuración).

Una opción similar, pero menos propensa a errores, es solo tener el singleton Lazy inicializando y darle una opción "predeterminada". Permita que la persona que llama establece una propiedad estática para alterar qué opción está construida, por lo que si se establece antes de la construcción del singleton, obtendrá un valor predeterminado diferente. Sin embargo, esto puede ser confuso, ya que nuevamente debe asegurarse de establecer la propiedad antes de acceder al singleton, o obtendrá un comportamiento inesperado.

Sé que es tarde para responder a la pregunta original, pero solo tenía este problema y así es como lo resolví. Puede que no sea ideal, pero parece funcionar. Creé un método init que debe llamarse antes de intentar usar la instancia de singleton.

public void Init(/*parameters*/)
{
        if (_isInitialized)
        {
            throw new InvalidOperationException("Component is already initialized!");
        }
        //do your work here
}

Cualquier otro acceso a la instancia de Singleton (propiedades de propiedades, establecidas, llamadas de método) lanzará una excepción de operación no válida que indica que el objeto no se inicializó.

Creo que esto hace lo que necesito, es menos confuso que GetInstance (Params) porque no existe riesgo de malinterpretar lo que hace el método. La desventaja es que no arrojará errores de tiempo de compilación, pero la primera ejecución sin la inicialización realizada lanzará una excepción, por lo que debería ser lo suficientemente bueno.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top