una - implementacion de interfaces c#
¿Interfaces separadas de la implementación de clase en proyectos separados? (8)
Creo que primero debe considerar si TODAS las interfaces pertenecen a la ''interfaz pública'' de su proyecto.
Si van a ser compartidos por múltiples proyectos, ejecutables y / o servicios, creo que es justo ponerlos en una asamblea por separado.
Sin embargo, si solo son para uso interno y para su comodidad, puede optar por mantenerlos en el mismo ensamblaje que la implementación, manteniendo así la cantidad total de ensamblajes relativamente baja.
Trabajamos en un proyecto de tamaño medio (3 desarrolladores durante más de 6 meses) y necesitamos tomar la siguiente decisión: nos gustaría tener interfaces separadas de la implementación concreta. El primero es almacenar la interfaz en un archivo separado.
Nos gustaría ir más allá y separar los datos aún más: nos gustaría tener un proyecto (CSPROJ) con interfaz en un archivo .CS más otro archivo .CS con clases de ayuda (como algunas clases públicas utilizadas en esta interfaz, algunos enums, etc.). Entonces, nos gustaría tener otro proyecto (CSPROJ) con un patrón de fábrica, implementación de interfaz concreta y otras clases de "trabajadores".
Cualquier clase que desee crear un objeto que implemente esta interfaz debe incluir el primer proyecto que contiene las interfaces y las clases públicas, no la implementación en sí.
Esta solución tiene una gran desventaja: multiplica el número de ensambles por 2, ya que tendría para cada proyecto "normal" un proyecto con interacción y uno con implementación.
¿Qué recomendarías? ¿Cree que es una buena idea colocar todas las interfaces en un proyecto separado en lugar de una interfaz en su propio proyecto?
El enfoque tiene sus pros y sus contras, y también tendrá que atenuar la decisión con la mejor forma en su enfoque arquitectónico.
En el lado "pro", puede lograr un nivel de separación para ayudar a aplicar correctamente las interfaces. Considere que si tiene un desarrollador de nivel medio o medio que está trabajando en implementaciones, las interfaces mismas se pueden definir en un proyecto en el que solo tienen acceso de lectura. Quizás un jefe de equipo o arquitecto de alto nivel es responsable del diseño y mantenimiento de las interfaces. Si estas interfaces se usan en múltiples proyectos, esto puede ayudar a mitigar el riesgo de cambios involuntarios en otros proyectos cuando solo se trabaja en uno. Además, si trabajas con proveedores externos a los que distribuyes una API, empaquetar las interfaces es algo muy bueno.
Obviamente, hay algunas desventajas. El ensamblaje no contiene código ejecutable. En algunas tiendas en las que he trabajado, han desaprobado la funcionalidad en un ensamblado, independientemente de la razón. Definitivamente hay gastos generales adicionales. Dependiendo de cómo configure su archivo físico y la estructura del espacio de nombres, es posible que tenga varios ensambles haciendo lo mismo (aunque no es necesario).
En una nota semialeatoria, asegúrese de documentar bien sus interfaces. La herencia de la documentación de las interfaces usando GhostDoc es algo hermoso.
Esta es una buena idea y aprecio algunas de las distinciones en la respuesta aceptada. Dado que ambas enumeraciones y especialmente las interfaces son, por su propia naturaleza, dependencias, esto les otorga propiedades especiales y las hace inmunes a las dependencias circulares e incluso a los gráficos de dependencia complejos que hacen que un sistema sea "frágil". Un colega mío una vez llamó a una técnica similar el "patrón de recuerdo" y nunca dejó de señalar una aplicación útil de la misma.
Ponga una interfaz en un proyecto que ya tiene muchas dependencias y esa interfaz, al menos con respecto al proyecto, viene con todas las dependencias del producto. Haga esto a menudo y es más probable que enfrente situaciones con dependencias circulares. La tentación es compensar con parches que de otro modo no serían necesarios.
Es como si las interfaces de acoplamiento con proyectos que tienen muchas dependencias los contaminaran. El propósito del diseño de las interfaces es quitar la pareja, por lo que en la mayoría de los casos tiene poco sentido acoplarlas a las clases.
No lo haría a menos que ofrezca un beneficio comprobado para la arquitectura de su aplicación.
Es bueno estar atento a la cantidad de ensamblajes que está creando . Incluso si una interfaz y su implementación se encuentran en el mismo conjunto, aún puede lograr el desacoplamiento que busca correctamente con un poco de disciplina.
Sí, creo que esta es una buena idea. En realidad, lo hacemos aquí todo el tiempo, y finalmente tenemos que hacerlo por una simple razón:
Usamos Remoting para acceder a la funcionalidad del servidor. Por lo tanto, los objetos remotos en el servidor deben implementar las interfaces y el código del cliente debe tener acceso a las interfaces para usar los objetos remotos.
En general, creo que estás más débilmente acoplado cuando colocas las interfaces en un proyecto separado, así que solo ve y hazlo. No es realmente un problema tener 2 ensamblajes, ¿o sí?
ADICIÓN:
Simplemente se me pasó por la cabeza: al colocar las interfaces en un ensamblaje separado, también obtiene la ventaja de poder reutilizar las interfaces si algunas de ellas son lo suficientemente generales.
Si una implementación de una interfaz termina teniendo muchas dependencias (en otros ensambles, etc.), tener la interfaz en un ensamble aislado puede simplemente ser una vida para los consumidores de mayor nivel.
Pueden hacer referencia a la interfaz sin inadvertidamente volverse dependiente de las dependencias de la implementación específica.
Solíamos tener un buen número de ensamblajes separados en nuestro código compartido. Con el tiempo, descubrimos que casi invariablemente hacíamos referencia a estos en grupos. Esto hizo más trabajo para los desarrolladores, y tuvimos que buscar para encontrar en qué ensamblado estaba una clase o interfaz. Terminamos combinando algunos de estos ensambles en función de los patrones de uso. La vida se hizo más fácil.
Aquí hay muchas consideraciones: ¿está escribiendo una biblioteca para desarrolladores, está implementando los archivos DLL a clientes externos, está usando la comunicación remota (gracias, Maximilian Mayerl) o escribiendo servicios WCF, etc. No hay una respuesta correcta, es depende
En general, estoy de acuerdo con Jeff Sternal: no rompa las asambleas a menos que ofrezcan un beneficio comprobado.
Yo distinguiría entre interfaces como esta:
Interfaces independientes cuyo propósito puede describir sin hablar del resto de su proyecto. Colóquelos en un único "conjunto de interfaz" dedicado, que probablemente sea referenciado por todos los demás ensambles de su proyecto. Ejemplos típicos:
ILogger
,IFileSystem
,IServiceLocator
.Interfaces de clase acopladas que realmente solo tienen sentido en el contexto de las clases de su proyecto. Póngalos en el mismo conjunto que las clases a las que están acoplados.
Un ejemplo: supongamos que su modelo de dominio tiene una clase
Banana
. Si recuperas plátanos a través de una interfazIBananaRepository
, entonces esa interfaz está estrechamente unida a los plátanos. Es imposible implementar o usar la interfaz sin saber algo sobre plátanos. Por lo tanto, es lógico que la interfaz resida en el mismo ensamblaje queBanana
.El ejemplo anterior tiene un acoplamiento técnico, pero el acoplamiento podría ser lógico. Por ejemplo, una interfaz
IFecesThrowingTarget
solo tiene sentido como colaborador de la claseMonkey
, incluso si la declaración de la interfaz no tiene ningún enlace técnico aMonkey
.
Mi respuesta depende de la noción de que está bien tener algún acoplamiento a las clases. Ocultar todo lo que hay detrás de una interfaz sería un error. A veces está bien simplemente "actualizar" una clase , en lugar de inyectarla o crearla a través de una fábrica.