nomenclatura - normas de codificación java
¿Deben colocarse las interfaces en un paquete separado? (14)
Colocar tanto la interfaz como la implementación es un lugar común, y no parece ser un problema.
Tomemos como ejemplo la API de Java: la mayoría de las clases tienen ambas interfaces y sus implementaciones incluidas en el mismo paquete.
Tomemos por ejemplo el paquete java.util
:
Contiene las interfaces como Set
, Map
, List
, y también tiene implementaciones como HashSet
, HashMap
y ArrayList
.
Además, los Javadocs están diseñados para funcionar bien en esas condiciones, ya que separa la documentación en las vistas Interfaces y Clases cuando se muestran los contenidos del paquete.
Tener paquetes solo para interfaces en realidad puede ser un poco excesivo, a menos que haya un enorme número de interfaces. Pero separar las interfaces en sus propios paquetes por el solo hecho de hacerlo suena como una mala práctica.
Si es necesario diferenciar el nombre de una interfaz de una implementación, se podría tener una convención de nomenclatura para facilitar la identificación de las interfaces:
Prefijo el nombre de la interfaz con un
I
Este enfoque se toma con las interfaces en .NET framework. Sería bastante fácil decir queIList
es una interfaz para una lista.Use el sufijo -
able
. Este enfoque se ve a menudo en la API de Java, comoComparable
,Iterable
ySerializable
por nombrar algunos.
Soy nuevo en un equipo que trabaja en un proyecto bastante grande, con muchos componentes y dependencias. Para cada componente, hay un paquete de interfaces
donde se colocan las interfaces expuestas para ese componente. ¿Es esta una buena practica?
Mi práctica habitual siempre ha sido las interfaces y las implementaciones van en el mismo paquete.
Creo que es importante tener en cuenta que para el marco OSGi, es mejor que estén en diferentes paquetes para que pueda exportar fácilmente un paquete completo mientras se ocultan los paquetes de implementación.
El libro Practical Software Engineering: Un enfoque de caso-estudio aboga por poner interfaces en proyectos / paquetes separados.
La arquitectura PCMEF + de la que habla el libro tiene los siguientes principios:
- Principio de dependencia hacia abajo (DDP)
- Principio de notificación hacia arriba (UNP)
- Principio de comunicación del vecino (NCP)
- Principio de Asociación Explícita (EAP)
- Principio de eliminación del ciclo (CEP)
- Principio de denominación de clase (CNP)
- Conocimiento del principio del paquete (APP)
La descripción de los principios # 3 y # 7 explica por qué es una buena idea:
El Principio de comunicación del vecino exige que un paquete solo se pueda comunicar directamente con su paquete vecino. Este principio asegura que el sistema no se desintegre en una red incompresible de objetos intercomunicados. Para hacer cumplir este principio, el mensaje que pasa entre objetos no vecinos usa delegación (Sección 9.1.5.1). En escenarios más complejos, el paquete conocido (Sección 9.1.8.2) se puede usar para agrupar interfaces para ayudar en la colaboración que involucra paquetes distantes.
El Principio del Paquete de Conocimiento es la consecuencia del Principio de Comunicación del Vecino. El paquete conocido consiste en interfaces que pasa un objeto, en lugar de objetos concretos, en argumentos a llamadas a métodos. Las interfaces se pueden implementar en cualquier paquete PCMEF. Esto permite de manera efectiva la comunicación entre paquetes no vecinos mientras se centraliza la administración de dependencias en un único paquete de conocidos. La necesidad de un paquete de conocidos se explicó en la Sección 9.1.8.2 y se vuelve a discutir a continuación en el contexto del PCMEF.
Vea este enlace: http://comp.mq.edu.au/books/pse/about_book/Ch9.pdf
En muchos marcos, como OSGi, casi tienes que hacerlo. Creo que esto promueve el acoplamiento más flexible, en el paquete en lugar del nivel de jar.
Estoy haciendo esto en un proyecto y me funciona bien por estas razones:
Las interfaces e implementaciones empaquetadas por separado son para un caso de uso diferente que para los distintos tipos de Mapa o Conjunto. No hay ninguna razón para tener un paquete solo para árboles (java.util.tree.Map, java.util.tree.Set). Es solo una estructura de datos estándar, por lo que conviértalo junto con las otras estructuras de datos. Sin embargo, si se trata de un juego de rompecabezas que tiene una interfaz de depuración realmente simple y una bonita interfaz de producción, como parte de su interfaz puede tener un com.your.app.skin.debug y un com.your.app .skin.pretty. No los pondría en el mismo paquete, porque hacen cosas diferentes y sé que recurriría a algunos SmurfNamingConvention (DebugAttackSurface, DebugDefenceSurface, PrettyAttackSurface, etc.) para crear un espacio de nombres informal para los dos si estuvieran en el mismo paquete.
Mi solución para el problema de encontrar interfaces relacionadas e implementaciones que están en paquetes separados es adoptar una configuración de nombres para mis paquetes. Por ejemplo, puedo tener todas mis interfaces en com.your.app.skin.framework, y saber que otros paquetes en el mismo nivel del árbol de paquetes son implementaciones. La desventaja es que esta es una convención no convencional. Honestamente, veré cuán buena es esta convención dentro de 6 meses :)
No uso esta técnica religiosamente. Hay interfaces que solo tienen sentido en una implementación particular. No los pego en el paquete de marco. Hay algunos paquetes en los que no parece que voy a crear 40 clases de implementación diferentes, así que no me molesto.
Mi aplicación usa guice y tiene muchas interfaces.
Las preguntas sobre el diseño del programa generalmente involucran beneficios e inconvenientes y no hay una respuesta única para todos. ¿Por qué usarías esta técnica en un pequeño programa de 200 líneas? Tiene sentido para mí, dadas mis otras opciones arquitectónicas, para mi problema específico. :)
Hacemos esto donde trabajo (es decir: poner la interfaz en un paquete y la implementación en otro) y la principal ventaja que obtenemos de esto es que podemos intercambiar fácilmente entre implementaciones.
Hay muchas buenas razones para colocar las interfaces en un paquete separado de la implementación. Por ejemplo, puede usar un contenedor que admita Inyección de dependencias para cablear las implementaciones necesarias en tiempo de ejecución, en cuyo caso solo la interfaz debe estar presente en el momento de la compilación y la implementación se puede suministrar en tiempo de ejecución. Alternativamente, es posible que desee proporcionar varias implementaciones (por ejemplo, utilizando implementaciones mock para pruebas) o versiones múltiples de una implementación particular en tiempo de ejecución (por ejemplo, para pruebas A / B, etc.). Para este tipo de casos de uso, es más conveniente empaquetar la interfaz y la implementación por separado.
Los prefiero en el mismo paquete. No tiene sentido crear un paquete específicamente para interfaces. Esto es especialmente redundante para equipos que simplemente aman sus prefijos y sufijos de interfaz (por ejemplo, el "I" y el "Impl" para Java).
Si existe la necesidad de publicar un conjunto de interfaces como API pública, tiene más sentido mantenerlas en un proyecto completamente separado y crear dependencias de proyectos en su lugar. Pero todo se reduce a la preferencia y conveniencia de la situación, supongo.
No tengo mucha experiencia en Java, pero me gusta hacer esto como una buena práctica en C # /. NET porque permite una expansión futura donde los ensamblajes con las clases concretas que implementan las interfaces no se pueden distribuir hasta el final. cliente porque están representados por una fábrica intermediaria o por el cable en un escenario de servicio web.
Normalmente pongo Interfaces con la implementación, sin embargo, puedo ver por qué querrá mantenerlos separados. Digamos, por ejemplo, que alguien quería volver a implementar clases basadas en sus interfaces, necesitarían un jar / lib / etc con su implementación en lugar de solo las interfaces. Con ellos separados, podría decir "Aquí está mi implementación de esa interfaz" y terminar con eso. Como dije, no es lo que hago, pero puedo ver por qué algunos podrían quererlo.
Póngalos en paquetes que reflejen sus proyectos. Está bien y es común juntar interfaces e implementaciones si son parte del mismo proyecto, pero si está escribiendo una API, entonces es probable que otra persona elija un nombre de paquete relevante para su proyecto.
En general, si es para el mismo proyecto, no veo ningún beneficio en mantener las interfaces en un paquete separado de sus impls. Si se está abarrotando, puede haber otros problemas de nomenclatura del paquete, independientemente de la disposición de la interfaz.
Para cualquier idioma, ponerlos juntos en el mismo paquete está bien. Lo importante es lo que está expuesto al mundo exterior y cómo se ve desde fuera. Nadie va a saber o importar si la implementación está en ese mismo paquete o no.
Miremos esta instancia particular.
Si tiene todas las cosas públicas en un paquete y las cosas privadas en otro paquete que no está públicamente expuesto, el cliente de la biblioteca ve un paquete. Si mueve las cosas privadas al paquete con las cosas expuestas públicamente, pero no las expone desde dentro del paquete, el cliente ve exactamente lo mismo.
Por lo tanto, esto tiene el olor de una regla sin un buen motivo: es tomar una decisión basada en algo que sea públicamente visible sin que esa decisión tenga ningún efecto sobre lo que es públicamente visible.
Dicho esto, si en algún caso en particular parece una buena idea dividir la interfaz y la implementación en paquetes separados, adelante y hazlo. Las razones para hacer esto que viene a la mente son que el paquete es enorme, o tiene una implementación alternativa en la que puede querer vincular en lugar de la estándar.
Sí, es una muy buena práctica, porque le permite publicar la interfaz sin publicar su implementación específica. Dicho esto, si no tiene necesidad de publicar interfaces externas, no hay problema para colocar las definiciones de la interfaz en el mismo paquete que la implementación.
Un argumento para colocar interfaces en diferentes paquetes es que es más fácil crear ''api'' jar que se pueden distribuir a los consumidores de su producto o servicio. Es perfectamente posible hacer esto con interfaces e implementaciones en conjunto, pero es más simple de ejecutar si están en paquetes diferentes.