2008-08-11 20 views
35

Antes que nada, sé cómo crear una aplicación Java. Pero siempre me ha intrigado sobre dónde ubicar mis clases. Hay proponentes para organizar los paquetes de una manera estrictamente orientada al dominio, otros por separado.¿Cómo debería estructurar una aplicación Java? ¿Dónde pongo mis clases?

yo mismo siempre han tenido problemas con

  • denominación,
  • colocación

Así,

  1. ¿Dónde poner sus constantes específicas de dominio (y cuál es el el mejor nombre para tal clase)?
  2. ¿Dónde colocas las clases para las cosas que son tanto de infraestructura como de dominio específico (por ejemplo, tengo una clase FileStorageStrategy, que almacena los archivos en la base de datos o en la base de datos)?
  3. ¿Dónde poner excepciones?
  4. ¿Hay alguna norma a la que pueda hacer referencia?
+0

Obviamente no hay una respuesta definitiva, pero después de usar maven2 durante un tiempo, llegué a aplicar la estructura dada, y por lo tanto, declaro que la respuesta maven es la misma. (Eso no significa que los otros estén equivocados, ni nada) Me acabo de dar cuenta de lo fácil que es no tener que pensar en las etapas iniciales de tu compilación, simplemente dejas caer tus fuentes y recursos en esos directorios y compila sin crear archivos ant y cosas así. – Mauli

Respuesta

21

Realmente me han gustado Standard Directory Layout de Maven.

Una de las ideas clave para mí es tener dos raíces de origen - una para el código de producción y otra para el código de prueba de este modo:

MyProject/src/main/java/com/acme/Widget.java 
MyProject/src/test/java/com/acme/WidgetTest.ava 

(aquí, tanto src/main/java y src/test/java son raíces de origen).

Ventajas:

  • Sus pruebas tienen el paquete (o "default") el acceso a nivel de sus clases bajo prueba.
  • Puede empaquetar fácilmente solo sus fuentes de producción en un JAR al colocar src/test/java como raíz de origen.

Una regla de oro sobre la colocación de clases y paquetes:

términos generales, los proyectos bien estructurados estará libre de circular dependencies. Aprenda cuándo son malos (y cuándo son not), y considere una herramienta como JDepend o SonarJ que lo ayudará a eliminarlos.

3

Los nombres de clase siempre deben ser descriptivos y autoexplicativos. Si tiene múltiples dominios de responsabilidad para sus clases, entonces probablemente deberían ser refactorizados.

Igual para sus paquetes. Deben agruparse por dominio de responsabilidad. Cada dominio tiene sus propias excepciones.

Por lo general, no te preocupes hasta que llegues a un punto en que se esté volviendo abrumador e hinchado. Luego siéntese y no codifique, simplemente refactorice las clases, compilando regularmente para asegurarse de que todo funcione. Luego continúa como lo hiciste antes.

2

Utilice paquetes para agrupar la funcionalidad relacionada.

Por lo general, en la parte superior de su árbol de paquetes se invierte su nombre de dominio (com.domain.subdomain) para garantizar la exclusividad, y generalmente habrá un paquete para su aplicación. Luego subdividir eso por área relacionada, por lo que su FileStorageStrategy podría entrar, digamos, com.domain.subdomain.myapp.storage, y luego podría haber implementaciones específicas/subclases/lo que sea en com.domain.subdomain.myapp.storage.file y com.domain.subdomain.myapp.storage.database. Estos nombres pueden ser bastante largos, pero import los mantiene a todos en la parte superior de los archivos y los IDE también pueden ayudar a administrarlos.

Las excepciones suelen ir en el mismo paquete que las clases que las arrojan, por lo que si tuviera, por ejemplo, FileStorageException, iría en el mismo paquete que FileStorageStrategy. Del mismo modo, una interfaz que define constantes estaría en el mismo paquete.

No existe realmente ningún estándar como tal, solo use el sentido común, y si todo se vuelve demasiado desordenado, refactorícese!

0

Una cosa que he hecho en el pasado: si amplío una clase, trataré de seguir sus convenciones. Por ejemplo, cuando trabaje con Spring Framework, tendré mis clases de MVC Controller en un paquete llamado com.mydomain.myapp.web.servlet.mvc . Si no extiendo algo, simplemente sigo con lo que es más simple. com.mydomain.domain para objetos de dominio (aunque si tiene un montón de objetos de dominio, este paquete podría ser un poco difícil de manejar). Para constantes específicas de dominio, las pongo como constantes públicas en la clase más relacionada.Por ejemplo, si tengo una clase "Miembro" y tengo una constante de longitud de nombre de miembro máxima, la pongo en la clase Miembro. Algunas tiendas hacen una clase de constantes separada, pero no veo el valor de agrupar números y cadenas sin relación en una sola clase. He visto otras tiendas intentar solucionar este problema creando clases SEPARATE Constants, pero eso parece una pérdida de tiempo y el resultado es demasiado confuso. Usando esta configuración, un proyecto grande con múltiples desarrolladores duplicará constantes por todas partes.

0

Me gusta dividir mis clases en paquetes que están relacionados entre sí.

Por ejemplo: Modelo Para las llamadas relacionadas con bases de datos

Ver clases que tienen que ver con lo que se ve

Control de clases de funcionalidad Core

Util Cualquier misceláneos. clases que se utilizan normalmente (funciones estáticas)

etc.

1

creo que sea sencillo y no creo que sea más. No te abstraigas demasiado y capas demasiado. Solo mantenlo ordenado, y a medida que crece, refactorizarlo es trivial. Una de las mejores características de los IDE es la refactorización, así que, ¿por qué no utilizarla y ahorrarle capacidad mental para resolver problemas relacionados con su aplicación, en lugar de problemas meta como la organización de códigos?

10

Soy un gran fan de las fuentes organizadas, así que siempre crear la siguiente estructura de directorios:

/src - for your packages & classes 
/test - for unit tests 
/docs - for documentation, generated and manually edited 
/lib - 3rd party libraries 
/etc - unrelated stuff 
/bin (or /classes) - compiled classes, output of your compile 
/dist - for distribution packages, hopefully auto generated by a build system 

En/src estoy usando los patrones de Java por defecto: Los nombres de paquetes que comienzan con su dominio (org .yourdomain.yourprojectname) y los nombres de clase que reflejan el aspecto de OOP que está creando con la clase (vea los otros comentaristas). nombres de paquetes comunes como util, modelo, vista, eventos son útiles, también.

que tienden a poner constantes para un tema específico en una clase propia, como SessionConstants o ServiceConstants en el mismo paquete de las clases de dominio.

2

Una cosa que encontré muy útil para las pruebas unitarias fue tener un myApp/src/y también myApp/test_src/directories. De esta forma, puedo colocar pruebas unitarias en los mismos paquetes que las clases que prueban, y aún puedo excluir fácilmente los casos de prueba cuando preparo mi instalación de producción.

2

Respuesta breve: dibuje la arquitectura de su sistema en términos de módulos, dibujados uno al lado del otro, con cada módulo dividido verticalmente en capas (por ejemplo, vista, modelo, persistencia). A continuación, utilice una estructura como com.mycompany.myapp.somemodule.somelayer, p. com.mycompany.myapp.client.view o com.mycompany.myapp.server.model.

Usando el nivel superior de los paquetes para la aplicación módulos, en el sentido anticuado-informática de modular programming, debería ser obvio. Sin embargo, en la mayoría de los proyectos en los que he trabajado terminamos olvidándonos de hacer eso, y terminamos con un lío de paquetes sin esa estructura de alto nivel. Este antipatrón suele mostrarse como un paquete para algo así como 'oyentes' o 'acciones' que agrupan clases que de otro modo no estarían relacionadas simplemente porque implementan la misma interfaz.

Dentro de un módulo, o en una aplicación pequeña, use paquetes para las capas de la aplicación. paquetes probables incluyen cosas como la siguiente, dependiendo de la arquitectura:

  • com.mycompany.myapp.view
  • com.mycompany.myapp.model
  • com.mycompany.myapp. servicios
  • com.mycompany.myapp.rules
  • com.mycompany.myapp.persi stence (o 'DAO' para los datos de capa de acceso)
  • com.mycompany.myapp.util (cuidado de este se utilizan como si fuera 'misc')

Dentro de cada una de estas capas, es natural agrupar las clases por tipo si hay muchas. Un anti-patrón común aquí es introducir innecesariamente demasiados paquetes y niveles de subpaquetes, de modo que solo haya unas pocas clases en cada paquete.

7

Donde estoy trabajando, estamos usando Maven 2 y tenemos un arquetipo bastante bueno para nuestros proyectos. El objetivo era obtener una buena separación de preocupaciones, así definimos una estructura de proyecto usando múltiples módulos (uno para cada aplicación 'capa'): - común: código común utilizado por las otras capas (p. Ej., I18n) - entidades: las entidades de dominio - repositorios: este módulo contiene las interfaces daos e implementaciones - services-intf: interfaces para los servicios (p. ej., UserService, ...) - servicios de impl: implementaciones de los servicios (por ejemplo, UserServiceImpl) - web: todo lo relacionado con el contenido de la web (por ejemplo, CSS, JSP, páginas JSF, ...) - ws: servicios web

Cada el módulo tiene sus propias dependencias (p. ej., los repositorios pueden tener jpa) y algunos son de todo el proyecto (por lo tanto, pertenecen al módulo común). Las dependencias entre los diferentes módulos de proyecto separan claramente las cosas (por ejemplo, la capa web depende de la capa de servicio pero no conoce la capa de repositorio).

Cada módulo tiene su propio paquete de base, por ejemplo, si el paquete de la aplicación es "com.foo.bar", entonces tenemos:

com.foo.bar.common 
com.foo.bar.entities 
com.foo.bar.repositories 
com.foo.bar.services 
com.foo.bar.services.impl 
... 

Cada módulo respeta la estructura estándar de proyecto Maven:

src\ 
    ..main\java 
    ...\resources 
    ..test\java 
    ...\resources 

Las pruebas unitarias para una capa determinada encuentran fácilmente su lugar en \ src \ test ... Todo lo que es específico del dominio tiene su lugar en el módulo de entidades. Ahora, algo así como una FileStorageStrategy debería entrar en el módulo de repositorios, ya que no necesitamos saber exactamente cuál es la implementación. En la capa de servicios, solo conocemos la interfaz del repositorio, no nos importa cuál es la implementación específica (separación de preocupaciones).

hay múltiples ventajas de este enfoque:

  • clara separación de las preocupaciones
  • cada módulo es empaquetable como un frasco (o una guerra en el caso del módulo web) y por lo tanto permite un código más fácil Reciclar (por ejemplo, podríamos instalar el módulo en el repositorio de Maven y reutilizarla en otro proyecto)
  • máxima independencia de cada parte del proyecto

sé que esto hace No respondo todas sus preguntas, pero creo que esto podría ponerlo en el camino correcto y podría ser útil para otros.

Cuestiones relacionadas