Para ser intercambiable y comprobable, normalmente los servicios con lógica deben tener una interfaz, p. Ej.
public class FooService: IFooService
{ ... }
En cuanto al diseño, estoy de acuerdo con esto, pero una de las cosas que me molesta con este enfoque es que para un servicio deberá declarar dos cosas (la clase y la interfaz), y en nuestro equipo, normalmente dos archivos (uno para la clase y uno para la interfaz). Otra incomodidad es la dificultad en la navegación porque el uso de "Ir a definición" en IDE (VS2010) apuntará a la interfaz (ya que otras clases se refieren a la interfaz), no a la clase real.
Estaba pensando que escribir IFooService en el mismo archivo que FooService reducirá la rareza anterior. Después de todo, IFooService y FooService están muy relacionados. ¿Es esta una buena practica? ¿Hay una buena razón por la que IFooService debe ubicarse en su propio archivo?
fuente
Respuestas:
No tiene que estar en su propio archivo, pero su equipo debe decidir sobre un estándar y cumplirlo.
Además, tiene razón en que "Ir a definición" lo lleva a la interfaz, pero si tiene instalado Resharper , es solo un clic para abrir una lista de clases / interfaces derivadas de esa interfaz, por lo que no es gran cosa. Es por eso que mantengo la interfaz en un archivo separado.
fuente
Creo que deberías mantenerlos separados. Como dijiste, la idea es seguir siendo comprobable e intercambiable. Al colocar la interfaz en el mismo archivo que su implementación, está asociando la interfaz con la implementación específica. Si decide crear un objeto simulado u otra implementación, la interfaz no estará separada lógicamente de FooService.
fuente
Según SOLID, no solo debe crear la interfaz, y no solo debe estar en un archivo diferente, sino que debe estar en un ensamblaje diferente.
¿Por qué? Debido a que cualquier cambio en un archivo fuente que se compila en un ensamblaje requiere la recompilación del ensamblaje, y cualquier cambio en un ensamblaje requiere la recompilación de cualquier ensamblaje dependiente. Entonces, si su objetivo, basado en SOLID, es poder reemplazar una implementación A con una implementación B, mientras que la clase C que depende de la interfaz I no tiene que saber la diferencia, debe asegurarse de que el ensamblaje con I en esto no cambia, protegiendo así los usos.
"Pero es solo una recompilación" Te escucho protestar. Bueno, eso puede ser, pero en la aplicación de su teléfono inteligente, que es más fácil en el ancho de banda de datos de sus usuarios; ¿descargar un binario que cambió o descargar ese binario y otros cinco con código que depende de él? No todos los programas están escritos para ser consumidos por computadoras de escritorio en una LAN. Incluso en ese caso, donde el ancho de banda y la memoria son baratos, las versiones de parches más pequeñas pueden tener valor porque son triviales para enviar a toda la LAN a través de Active Directory o capas de administración de dominio similares; sus usuarios esperarán solo unos segundos para que se aplique la próxima vez que inicien sesión en lugar de unos minutos para que todo se reinstale. Sin mencionar que, cuantos menos ensambles se deben volver a compilar al construir un proyecto, más rápido se construirá,
Ahora, el descargo de responsabilidad: esto no siempre es posible o factible de hacer. La forma más fácil de hacer esto es crear un proyecto centralizado de "interfaces". Esto tiene sus propios inconvenientes; el código se vuelve menos reutilizable porque el proyecto de interfaz Y el proyecto de implementación deben ser referenciados en otras aplicaciones que reutilicen la capa de persistencia u otros componentes clave de su aplicación. Puede superar ese problema dividiendo las interfaces en ensamblajes más estrechamente acoplados, pero luego tiene más proyectos en su aplicación, lo que hace que una compilación completa sea muy dolorosa. La clave es el equilibrio y mantener el diseño débilmente acoplado; por lo general, puede mover los archivos según sea necesario, por lo que cuando vea que una clase necesitará muchos cambios o que se necesitarán nuevas implementaciones de una interfaz regularmente (tal vez para interactuar con versiones de otro software recientemente admitidas,
fuente
¿Por qué es molesto tener archivos separados? Para mí, es mucho más ordenado y limpio. Es común crear una subcarpeta llamada "Interfaces" y pegar sus archivos IFooServer.cs allí, si desea ver menos archivos en su Explorador de soluciones.
La razón por la que la interfaz se define en su propio archivo es la misma razón por la que las clases se definen generalmente en su propio archivo: la gestión de proyectos es más simple cuando su estructura lógica y estructura de archivos son idénticas, por lo que siempre sabe qué archivo se define una clase determinada in. Esto puede facilitarle la vida al depurar (los rastreos de la pila de excepciones generalmente le dan números de archivo y línea) o al fusionar el código fuente en un repositorio de control de fuente.
fuente
A menudo es una buena práctica dejar que sus archivos de código contengan una sola clase o una única interfaz. Pero estas prácticas de codificación son un medio para lograr un fin: estructurar mejor su código y facilitar su trabajo. Si a usted y a su equipo les resulta más fácil trabajar si las clases se mantienen junto con sus interfaces, de todas maneras.
Personalmente, prefiero tener la interfaz y la clase en el mismo archivo cuando solo hay una clase que implementa la interfaz, como en su caso.
En cuanto a los problemas que tiene con la navegación, le recomiendo ReSharper . Contiene algunos atajos muy útiles para saltar directamente al método que implementa un método de interfaz específico.
fuente
Hay muchas veces en las que desea que su interfaz esté no solo en un archivo separado para la clase, sino incluso en un ensamblaje separado por completo.
Por ejemplo, una interfaz de contrato de servicio WCF puede ser compartida por el cliente y el servicio si tiene control sobre ambos extremos del cable. Al mover la interfaz a su propio ensamblaje, tendrá menos dependencias de ensamblaje propias. Esto facilita mucho el consumo del cliente, aflojando el acoplamiento con su implementación.
fuente
Raramente, si alguna vez, tiene sentido tener una única implementación de una interfaz 1 . Si coloca una interfaz pública y una clase pública que implementa esa interfaz en el mismo archivo, es muy probable que no necesite una interfaz.
Cuando la clase que co-ubica con la interfaz es abstracta , y sabe que todas las implementaciones de su interfaz deben heredar esa clase abstracta, tiene sentido ubicar las dos en el mismo archivo. Todavía debe analizar su decisión de usar una interfaz: pregúntese si una clase abstracta por sí sola estaría bien y descarte la interfaz si la respuesta es afirmativa.
Sin embargo, en general, debe apegarse a la estrategia "una clase / interfaz pública corresponde a un archivo": es fácil de seguir y hace que su árbol de origen sea más fácil de navegar.
1 Una excepción notable es cuando necesita tener una interfaz para fines de prueba, porque su elección de marco de imitación impuso este requisito adicional en su código.
fuente
sealed
. Si sospecha que en algún momento en el futuro puede agregar una segunda subclase, puede poner una interfaz de inmediato. PD: un asistente de refactorización de calidad decente puede ser suyo a un precio modesto de una sola licencia ReSharper :)virtual
.Las interfaces pertenecen a sus clientes, no a sus implementaciones, como se define en los Principios, prácticas y patrones ágiles de Robert C. Martin. Por lo tanto, combinar la interfaz y la implementación en el mismo lugar es contrario a su principio.
El código del cliente depende de la interfaz. Esto permite la posibilidad de compilar e implementar el código del cliente y la interfaz sin la implementación. De lo que puede tener diferentes implementaciones que funcionan como complementos para el código del cliente.
ACTUALIZACIÓN: Este no es un principio ágil solo aquí. La Banda de los Cuatro en los Patrones de Diseño, en el '94, ya está hablando de clientes que se adhieren a las interfaces y programan a las interfaces. Su punto de vista es similar.
fuente
Personalmente no me gusta el "yo" frente a una interfaz. Como usuario de ese tipo, no quiero ver si se trata de una interfaz o no. El tipo es lo interesante. En términos de dependencias, su FooService es UNA posible implementación de IFooService. La interfaz debe estar cerca del lugar donde se usa. Por otro lado, la implementación debe estar en un lugar donde pueda cambiarse fácilmente sin afectar al cliente. Por lo tanto, preferiría dos archivos, normalmente.
fuente
new
, pero por otro lado, puedo usarlo de manera co-o contra-variante. YI
es una convención de nomenclatura establecida en .Net, por lo que es una buena razón para cumplirla, aunque solo sea para mantener la coherencia con otros tipos.I
interfaz fue solo la introducción a mis argumentos sobre la separación en dos archivos. El código es mejor legible y hace que la inversión de las dependencias sea más clara.I
es normal en su entorno: ¡Úselo! (Pero no me gusta :))La codificación de interfaces puede ser mala, de hecho se trata como un antipatrón para ciertos contextos y no es una ley. Por lo general, un buen ejemplo de codificación para interfaces anti-patrón es cuando tiene una interfaz que solo tiene una implementación en su aplicación. Otra sería si el archivo de interfaz se vuelve tan molesto que tiene que ocultar su declaración en el archivo de la clase implementada.
fuente
Poner una clase y una interfaz en el mismo archivo no limita cómo se puede usar. Una interfaz todavía se puede usar para simulacros, etc. de la misma manera, incluso si está en el mismo archivo que una clase que la implementa. La pregunta podría percibirse simplemente como una cuestión de conveniencia organizacional, en cuyo caso diría que haga lo que sea que le haga la vida más fácil.
Por supuesto, uno podría argumentar que tener los dos en el mismo archivo podría llevar a los incautos a considerar que están más acoplados programáticamente de lo que realmente son, lo cual es un riesgo.
Personalmente, si me encuentro con una base de código que usa una convención sobre la otra, no me preocuparía demasiado de ninguna manera.
fuente