Question

Tout d'abord, je sais comment créer une application Java.Mais j’ai toujours été perplexe quant à l’endroit où placer mes cours.Certains sont partisans d'une organisation des packages strictement orientée domaine, d'autres sont séparés par niveau.

J'ai moi-même toujours eu des problèmes avec

  • appellation,
  • placement

Donc,

  1. Où placez-vous les constantes spécifiques à votre domaine (et quel est le meilleur nom pour une telle classe) ?
  2. Où placez-vous les classes pour les éléments à la fois spécifiques à l'infrastructure et au domaine (par exemple, j'ai une classe FileStorageStrategy, qui stocke les fichiers soit dans la base de données, soit dans la base de données) ?
  3. Où mettre les exceptions ?
  4. Existe-t-il des normes auxquelles je peux me référer ?
Était-ce utile?

La solution

J'en suis vraiment venu à aimer celui de Maven Disposition du répertoire standard.

L'une des idées clés pour moi est d'avoir deux racines sources - une pour le code de production et une pour le code de test comme ceci :

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

(ici, src/main/java et src/test/java sont des racines sources).

Avantages :

  • Vos tests disposent d'un accès au niveau package (ou "par défaut") à vos classes testées.
  • Vous pouvez facilement regrouper uniquement vos sources de production dans un JAR en supprimant src/test/java en tant que racine source.

Une règle générale concernant le placement des classes et les forfaits :

D'une manière générale, les projets bien structurés seront exempts de dépendances circulaires.Apprenez quand ils sont mauvais (et quand ils le sont pas), et considérons un outil comme JDépend ou SonarJ cela vous aidera à les éliminer.

Autres conseils

Je suis un grand fan des sources organisées, je crée donc toujours la structure de répertoires suivante :

/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

Dans /src, j'utilise les modèles Java par défaut :Noms de packages commençant par votre domaine (org.yourdomain.yourprojectname) et noms de classe reflétant l'aspect POO que vous créez avec la classe (voir les autres commentateurs).Noms de packages courants comme util, modèle, voir, événements sont également utiles.

J'ai tendance à mettre des constantes pour un sujet spécifique dans une propre classe, comme Constantes de session ou Constantes de service dans le même package des classes de domaine.

Là où je travaille, nous utilisons Maven 2 et nous avons un archétype plutôt sympa pour nos projets.Le but étant d'obtenir une bonne séparation des préoccupations, nous avons défini une structure de projet utilisant plusieurs modules (un pour chaque « couche ») applicative :- commun:Code commun utilisé par les autres couches (par exemple, i18n) - entités:Les entités de domaine - Référentiels:Ce module contient les interfaces et les implémentations DAOS - Services-INTF:Interfaces pour les services (par exemple, userService, ...) - Services-Impl:Implémentations des services (par exemple, UserServiceImpl) - Web:Tout ce qui concerne le contenu Web (par exemple, CSS, JSPS, JSF Pages, ...) - WS:services Web

Chaque module a ses propres dépendances (par exemple, les référentiels peuvent avoir jpa) et certaines s'étendent à l'échelle du projet (elles appartiennent donc au module commun).Les dépendances entre les différents modules du projet séparent clairement les choses (par exemple, la couche Web dépend de la couche service mais ne connaît pas la couche référentiel).

Chaque module possède son propre package de base, par exemple si le package de l'application est "com.foo.bar", alors nous avons :

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

Chaque module respecte la structure standard du projet Maven :

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

Les tests unitaires pour une couche donnée trouvent facilement leur place sous \src est...Tout ce qui est spécifique au domaine a sa place dans le module entités.Maintenant, quelque chose comme FileStorageStrategy devrait aller dans le module des référentiels, puisque nous n'avons pas besoin de savoir exactement quelle est l'implémentation.Dans la couche services, nous ne connaissons que l'interface du référentiel, peu nous importe quelle est l'implémentation spécifique (séparation des préoccupations).

Les avantages de cette approche sont multiples :

  • séparation claire des préoccupations
  • chaque module est empaquetable sous forme de jar (ou de war dans le cas du module web) et permet ainsi une réutilisation plus facile du code (par exemple, nous pourrions installer le module dans le référentiel maven et le réutiliser dans un autre projet)
  • indépendance maximale de chaque partie du projet

Je sais que cela ne répond pas à toutes vos questions, mais je pense que cela pourrait vous mettre sur la bonne voie et s'avérer utile à d'autres.

Les noms de classe doivent toujours être descriptifs et explicites.Si vous avez plusieurs domaines de responsabilité pour vos cours, ils devraient probablement être refactorisés.

De même pour vos forfaits.Ils doivent être regroupés par domaine de responsabilité.Chaque domaine a ses propres exceptions.

En général, ne vous inquiétez pas jusqu'à ce que vous arriviez à un point où cela devient écrasant et gonflé.Ensuite, asseyez-vous et ne codez pas, refactorisez simplement les classes, en compilant régulièrement pour vous assurer que tout fonctionne.Continuez ensuite comme vous l'avez fait auparavant.

Utilisez des packages pour regrouper les fonctionnalités associées.

Habituellement, en haut de votre arborescence de packages se trouve votre nom de domaine inversé (com.domain.subdomain) pour garantir l'unicité, et il y aura généralement un package pour votre application.Ensuite, subdivisez cela par domaine connexe, de sorte que votre FileStorageStrategy pourrait entrer, disons, com.domain.subdomain.myapp.storage, et puis il pourrait y avoir des implémentations/sous-classes/quoi que ce soit dans com.domain.subdomain.myapp.storage.file et com.domain.subdomain.myapp.storage.database.Ces noms peuvent être assez longs, mais import les garde tous en haut des fichiers et les IDE peuvent également aider à gérer cela.

Les exceptions vont généralement dans le même package que les classes qui les lancent, donc si vous aviez, disons, FileStorageException ça irait dans le même paquet que FileStorageStrategy.De même, une interface définissant des constantes serait dans le même package.

Il n'y a pas vraiment de norme en tant que telle, faites simplement preuve de bon sens, et si tout devient trop compliqué, refactorisez !

Une chose que j'ai trouvée très utile pour les tests unitaires était d'avoir un répertoire myApp/src/ et également myApp/test_src/.De cette façon, je peux placer les tests unitaires dans les mêmes packages que les classes qu'ils testent, et pourtant je peux facilement exclure les cas de test lorsque je prépare mon installation de production.

Réponse courte:dessinez votre architecture système en termes de modules, dessinés côte à côte, chaque module étant découpé verticalement en couches (par ex.vue, modèle, persistance).Utilisez ensuite une structure comme com.mycompany.myapp.somemodule.somelayer, par exemple. com.mycompany.myapp.client.view ou com.mycompany.myapp.server.model.

Utiliser le niveau supérieur de packages pour l'application modules, au sens informatique ancien de programmation modulaire, devrait être évident.Cependant, sur la plupart des projets sur lesquels j'ai travaillé, nous finissons par oublier de le faire et nous nous retrouvons avec un désordre de packages sans cette structure de niveau supérieur.Cet anti-modèle se présente généralement comme un package pour quelque chose comme des « auditeurs » ou des « actions » qui regroupent des classes autrement sans rapport simplement parce qu'elles implémentent la même interface.

Au sein d'un module ou dans une petite application, utilisez des packages pour les couches d'application.Les packages probables incluent les éléments suivants, en fonction de l'architecture :

  • com.mycompany.myapp.view
  • com.mycompany.myapp.model
  • com.mycompany.myapp.services
  • com.mycompany.myapp.rules
  • com.mycompany.myapp.persistence (ou 'dao' pour couche d'accès aux données)
  • com.mycompany.myapp.util (attention, cela n'est pas utilisé comme s'il s'agissait de « misc »)

Au sein de chacune de ces couches, il est naturel de regrouper les classes par type s’il y en a beaucoup.Un anti-modèle courant ici consiste à introduire inutilement trop de packages et de niveaux de sous-packages afin qu'il n'y ait que quelques classes dans chaque package.

Je pense que rester simple et ne pas trop y penser.Ne faites pas trop d'abstrait et ne superposez pas trop.Gardez-le simplement propre, et à mesure qu'il grandit, le refactoriser est trivial.L'une des meilleures fonctionnalités des IDE est la refactorisation, alors pourquoi ne pas l'utiliser et économiser votre cerveau pour résoudre les problèmes liés à votre application, plutôt que les méta-problèmes comme l'organisation du code.

Une chose que j'ai faite dans le passé : si je prolonge un cours, j'essaierai de suivre leurs conventions.Par exemple, lorsque je travaille avec le framework Spring, j'aurai mes classes de contrôleur MVC dans un package appelé com.mydomain.myapp.web.servlet.mvc si je n'étends pas quelque chose, je vais simplement avec ce qui est le plus simple.com.mydomain.domain pour les objets de domaine (bien que si vous avez une tonne d'objets de domaine, ce package pourrait devenir un peu lourd).Pour les constantes spécifiques à un domaine, je les mets en fait comme constantes publiques dans la classe la plus associée.Par exemple, si j’ai une classe « Membre » et que j’ai une longueur maximale de nom de membre constante, je la mets dans la classe Member.Certains magasins créent une classe Constants distincte, mais je ne vois pas l'intérêt de regrouper des nombres et des chaînes sans rapport dans une seule classe.J'ai vu d'autres magasins essayer de résoudre ce problème en créant des classes de constantes SÉPARÉES, mais cela semble être une perte de temps et le résultat est trop déroutant.En utilisant cette configuration, un grand projet avec plusieurs développeurs dupliquera des constantes partout.

J'aime diviser mes cours en packages liés les uns aux autres.

Par exemple:Modèle Pour les appels liés à la base de données

Voir Des cours qui traitent de ce que vous voyez

Contrôle Classes de fonctionnalités de base

Utilitaire Tout divers.classes utilisées (généralement des fonctions statiques)

etc.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top