Patrón de diseño - DLL por estrategia

8

Por lo general, me encontré diseñando mi aplicación de la siguiente manera:

  1. Una DLL que contiene interfaces para un subsistema deseado. Por ejemplo, Company.Framework.Persistence.dll.
  2. Una nueva DLL por cada estrategia (o implementaciones ) de dicho subsistema. Por ejemplo:
    • Company.Framework.Persistence.MSSQL.dll
    • Company.Framework.Persistence.MySQL.dll
    • Company.Framework.Persistence.FileSystem.dll

Esto dará como resultado una solución muy grande con muchos proyectos, pero por otro lado, le daría al consumidor la oportunidad de elegir la DLL adecuada para sus necesidades.

Si tuviéramos que llamar a un solo archivo DLL Company.Framework.Persistence.dll, el consumidor tendría que cargar muchas estrategias que quizás nunca use. Tener una DLL modularizada resolvería este problema.

¿Es esta una buena práctica? ¿Hay alguna desventaja con este diseño?

Matias Cicero
fuente
1
¿Hay alguna desventaja en incluir todo? El almacenamiento de la computadora es barato . Mientras la complejidad para el usuario sea baja, ¿realmente importa?
2
Siempre puede combinar todos los ensamblajes en una mega-DLL como paso de compilación: stackoverflow.com/questions/8077570/…
Den
relacionado (enfoque similar): codeproject.com/Articles/666492/Dynamic-Load-NET-Assembly
Nick Alexeev

Respuestas:

3

Creo que las ventajas de este enfoque superan con creces cualquier desventaja.

Lo que está logrando aquí es más o menos una "implementación" perfecta de la entrada Ia SOLIDtravés del Stairwaypatrón, es decir, su aplicación depende "abajo" de una interfaz definida en Company.Framework.Persistence.dlly las implementaciones individuales también dependen "arriba" en esta abstracción.

Esto significa que su aplicación está muy desacoplada de cualquier detalle de implementación (por supuesto, generalmente querrá componer el gráfico de tiempo de ejecución real utilizando un Contenedor IOC de algún tipo). en desbordamiento de pila:

Ejemplo de patrón de escalera

En el libro Adaptive Code a través de C #, el autor habla sobre este enfoque y lo menciona específicamente como algo que siempre debe hacerse porque proporciona un nivel tan alto de desacoplamiento. ( ejemplo )

Otra posible ventaja es poder parchear implementaciones individuales sin preocuparse de que pueda haber afectado a otros, aunque esta es bastante menor una vez que haya sido diligente con sus pruebas de regresión; También poder implementar las implementaciones individuales en subcarpetas que también pueden contener las versiones específicas de las dependencias de terceros que puedan necesitar, probablemente ayudará a mantener las cosas bien organizadas.

La única desventaja real que se me ocurre con este enfoque es que, en teoría, es posible cambiar la interfaz Company.Framework.Persistence.dll(junto con los archivos binarios de su aplicación) y descuidar la actualización de los dlls de implementación correspondientes que generarán errores de tiempo de ejecución para sus usuarios.

Habiendo sido culpable de hacer exactamente esto en el pasado, puedo decir que esto es realmente solo algo que puede suceder si eres muy descuidado :)

Stephen Byrne
fuente
1

Yo también lo hago así.

Los proyectos / dlls son esencialmente gratuitos y hacen que el código sea más legible y fácil de usar.

Sé que las personas usan una sola DLL grande y se diferencian con espacios de nombre. Pero como usted dice que tienen que implementar código no utilizado, no veo ningún beneficio para la práctica y muchas desventajas, como

  • cambiar a una implementación requiere recompilar las demás
  • el código no utilizado se implementa para vivir (riesgo de errores)
  • el código de prueba se implementa en vivo (simulacros, etc., riesgo de errores, configuración incorrecta)
  • el código obsoleto requiere una refactorización para eliminarlo (digamos que ya no usamos MySQL)
  • tiene que probar el código no utilizado antes de la implementación (estamos probando, ¿verdad?)
  • la refactorización puede causar un error de compilación en un componente no utilizado (digamos que cambiamos una interfaz)

Podría cortar esquinas y poner la implementación concreta con la interfaz para aplicaciones pequeñas si evita un proyecto que contiene una sola interfaz. Pero normalmente encuentro que las interfaces van con los modelos. Entonces tendría

  • Company.Framework.Models.dll (incluye interfaz para persistencia)
  • Company.Framework.Persistence.MySQL.dll (modelos de referencia, pero necesita de todos modos)
  • Company.Framework.Persistence.Mock.dll (modelos de referencia, pero necesita de todos modos)

o (¡mal acceso directo!)

  • Company.Framework.Models.dll (sin incluir interfaces)
  • Company.Framework.Persistence.MySQL.dll (incluye interfaz de persistencia, modelos de referencia)
  • Company.Framework.Persistence.Mock.dll (modelos de referencia y sql, pero no está implementado para vivir)

Por supuesto, es bastante simple refactorizar las interfaces si la aplicación aumenta en tamaño / complejidad

Ewan
fuente
0

La ventaja de la estrategia dos es minimizar dll hell.

Por lo general, Company.Framework.Persistence.MySQL.dll dependerá de alguna dll para interactuar con MySql. Si no tengo interés en MySql, ¿por qué debería descargar el dll desde MySql?

Digamos que su marco soportaba 20 proveedores de almacenamiento diferentes. La mayoría de los usuarios solo usan uno. Por lo tanto, todos los usuarios tienen que ir y obtener 19 dll que nunca van a usar solo para compilar su marco.

Al seguir la estrategia dos, permite que sus usuarios solo instalen los dll que van a usar y, por lo tanto, minimizan el infierno de dll.

Esben Skov Pedersen
fuente