Recientemente, he llegado a preferir mapear relaciones 1-1 usando en Dictionaries
lugar de Switch
declaraciones. Creo que es un poco más rápido de escribir y más fácil de procesar mentalmente. Desafortunadamente, cuando se asigna a una nueva instancia de un objeto, no quiero definirlo así:
var fooDict = new Dictionary<int, IBigObject>()
{
{ 0, new Foo() }, // Creates an instance of Foo
{ 1, new Bar() }, // Creates an instance of Bar
{ 2, new Baz() } // Creates an instance of Baz
}
var quux = fooDict[0]; // quux references Foo
Dada esa construcción, desperdicié ciclos de CPU y memoria creando 3 objetos, haciendo lo que sus constructores pudieran contener, y solo terminé usando uno de ellos. También creo que mapear otros objetos fooDict[0]
en este caso hará que hagan referencia a lo mismo, en lugar de crear una nueva instancia de Foo
lo previsto. Una solución sería usar una lambda en su lugar:
var fooDict = new Dictionary<int, Func<IBigObject>>()
{
{ 0, () => new Foo() }, // Returns a new instance of Foo when invoked
{ 1, () => new Bar() }, // Ditto Bar
{ 2, () => new Baz() } // Ditto Baz
}
var quux = fooDict[0](); // equivalent to saying 'var quux = new Foo();'
¿Esto está llegando a un punto donde es demasiado confuso? Es fácil perderse eso ()
al final. ¿O es el mapeo a una función / expresión una práctica bastante común? La alternativa sería usar un interruptor:
IBigObject quux;
switch(someInt)
{
case 0: quux = new Foo(); break;
case 1: quux = new Bar(); break;
case 2: quux = new Baz(); break;
}
¿Qué invocación es más aceptable?
- Diccionario, para búsquedas más rápidas y menos palabras clave (mayúsculas y minúsculas)
- Switch: más comúnmente encontrado en el código, no requiere el uso de un objeto Func <> para la indirección.
fuente
fooDict[0] is fooDict[0]
). tanto con el lambda y el interruptor este no es el casoRespuestas:
Esa es una versión interesante del patrón de fábrica . Me gusta la combinación del Diccionario y la expresión lambda; me hizo mirar ese contenedor de una nueva manera.
Estoy ignorando la preocupación en su pregunta sobre los ciclos de CPU, como mencionó en los comentarios de que el enfoque no lambda no proporciona lo que necesita.
Creo que cualquiera de los enfoques (switch vs. Dictionary + lambda) va a estar bien. La única limitación es que al usar el Diccionario, está limitando los tipos de entradas que podría recibir para generar la clase devuelta.
El uso de una declaración de cambio le proporcionaría más flexibilidad en los parámetros de entrada. Sin embargo, si esto tiene que ser un problema, puede envolver el Diccionario dentro de un método y obtener el mismo resultado final.
Si es nuevo para su equipo, comente el código y explique lo que está sucediendo. Solicite una revisión del código del equipo, guíelos a través de lo que se hizo y hágales saber. Aparte de eso, se ve bien.
fuente
case 0: quux = new Foo(); break;
se convierte encase 0: return new Foo();
lo que es francamente tan fácil de escribir y mucho más fácil de leer que{ 0, () => new Foo() }
C # 4.0 le ofrece la
Lazy<T>
clase, que es similar a su propia segunda solución, pero grita "Inicialización diferida" más explícitamente.fuente
Estilísticamente creo que la legibilidad es igual entre ellos. Es más fácil hacer una inyección de dependencia con el
Dictionary
.No olvide que debe verificar si la clave existe al usar el
Dictionary
, y debe proporcionar un respaldo si no es así.Preferiría la
switch
declaración para rutas de código estático y lasDictionary
rutas de código dinámico (donde puede agregar o eliminar entradas). El compilador podría realizar algunas optimizaciones estáticas con elswitch
que no puede con elDictionary
.Curiosamente, este
Dictionary
patrón es lo que la gente a veces hace en Python, porque Python carece de laswitch
declaración. De lo contrario, usan cadenas if-else.fuente
En general, no preferiría ninguno de los dos.
Lo que sea que esté consumiendo esto debería funcionar con a
Func<int, IBigObject>
. Entonces la fuente de su mapeo puede ser un Diccionario o un método que tenga una declaración de cambio o una llamada al servicio web o alguna búsqueda de archivos ... lo que sea.En cuanto a la implementación, preferiría el Diccionario ya que se refactoriza más fácilmente de 'diccionario de código duro, clave de búsqueda, resultado de retorno' a 'cargar diccionario desde archivo, clave de búsqueda, resultado de retorno'.
fuente