Nous implémentons un adaptateur pour Jaxen (une bibliothèque XPath pour Java) qui nous permet d'utiliser XPath pour accéder au modèle de données de notre application.
Cela se fait en implémentant des classes qui mappent des chaînes (transmises depuis Jaxen) en éléments de notre modèle de données. Nous estimons que nous aurons besoin d'environ 100 classes avec plus de 1000 comparaisons de chaînes au total.
Je pense que la meilleure façon de le faire est de simples instructions if / else avec les chaînes écrites directement dans le code - plutôt que de définir chaque chaîne comme une constante. Par exemple:
public Object getNode(String name) {
if ("name".equals(name)) {
return contact.getFullName();
} else if ("title".equals(name)) {
return contact.getTitle();
} else if ("first_name".equals(name)) {
return contact.getFirstName();
} else if ("last_name".equals(name)) {
return contact.getLastName();
...
Cependant, on m'a toujours enseigné que nous ne devons pas incorporer des valeurs de chaîne directement dans le code, mais plutôt créer des constantes de chaîne. Cela ressemblerait à quelque chose comme ceci:
private static final String NAME = "name";
private static final String TITLE = "title";
private static final String FIRST_NAME = "first_name";
private static final String LAST_NAME = "last_name";
public Object getNode(String name) {
if (NAME.equals(name)) {
return contact.getFullName();
} else if (TITLE.equals(name)) {
return contact.getTitle();
} else if (FIRST_NAME.equals(name)) {
return contact.getFirstName();
} else if (LAST_NAME.equals(name)) {
return contact.getLastName();
...
Dans ce cas, je pense que c'est une mauvaise idée. La constante ne sera utilisée qu'une seule fois, dans la getNode()
méthode. L'utilisation directe des chaînes est tout aussi facile à lire et à comprendre que l'utilisation des constantes et nous évite d'écrire au moins mille lignes de code.
Y a-t-il donc une raison de définir des constantes de chaîne pour un usage unique? Ou est-il acceptable d'utiliser directement des chaînes?
PS. Avant que quiconque ne suggère d'utiliser des énumérations à la place, nous avons fait un prototype, mais la conversion d'énumérations est 15 fois plus lente que la simple comparaison de chaînes, donc ce n'est pas envisagé.
Conclusion: Les réponses ci-dessous ont élargi la portée de cette question au-delà des constantes de chaîne, j'ai donc deux conclusions:
- Il est probablement correct d'utiliser les chaînes directement plutôt que les constantes de chaîne dans ce scénario, mais
- Il existe des moyens d'éviter d'utiliser des chaînes, ce qui pourrait être mieux.
Je vais donc essayer la technique du wrapper qui évite complètement les cordes. Malheureusement, nous ne pouvons pas utiliser l'instruction de changement de chaîne car nous ne sommes pas encore sur Java 7. En fin de compte, cependant, je pense que la meilleure réponse pour nous est d'essayer chaque technique et d'évaluer ses performances. La réalité est que si une technique est clairement plus rapide, nous la choisirons probablement quelle que soit sa beauté ou son respect des conventions.
la source
switch
étiquettes. Utilisez un interrupteur au lieu deif
cascades.Réponses:
Essaye ça. La réflexion initiale est certainement coûteuse, mais si vous allez l'utiliser plusieurs fois, ce que je pense que vous le ferez, c'est certainement une meilleure solution que ce que vous proposez. Je n'aime pas utiliser la réflexion, mais je me retrouve à l'utiliser quand je n'aime pas l'alternative à la réflexion. Je pense que cela sauvera beaucoup de maux de tête à votre équipe, mais vous devez passer le nom de la méthode (en minuscules).
En d'autres termes, plutôt que de passer "nom", vous passeriez "nom complet" car le nom de la méthode get est "getFullName ()".
Si vous devez accéder aux données contenues dans les membres de contact, vous pouvez envisager de créer une classe wrapper pour contact qui dispose de toutes les méthodes pour accéder aux informations requises. Cela serait également utile pour garantir que les noms des champs d'accès resteront toujours les mêmes (c'est-à-dire si la classe wrapper a getFullName () et que vous appelez avec fullname, cela fonctionnera toujours même si getFullName () du contact a été renommé - il provoquerait une erreur de compilation avant de vous permettre de le faire).
Cette solution m'a sauvé plusieurs fois, à savoir quand je voulais avoir une seule représentation de données à utiliser dans les tables de données jsf et quand ces données devaient être exportées dans un rapport à l'aide de jasper (qui ne gère pas bien les accesseurs d'objets compliqués dans mon expérience) .
la source
.invoke()
, car il supprime entièrement les constantes de chaîne. Je ne suis pas si désireux de réfléchir à l'exécution pour configurer la carte, bien que peut-être que l'exécutiongetMethodMapping()
dans unstatic
bloc soit OK pour que cela se produise au démarrage plutôt qu'une fois le système en cours d'exécution.Si possible, utilisez Java 7 qui vous permet d'utiliser des chaînes dans les
switch
instructions.Depuis http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
Je n'ai pas mesuré, mais je crois que les instructions switch se compilent dans une table de saut au lieu d'une longue liste de comparaisons. Cela devrait être encore plus rapide.
Concernant votre question réelle: si vous ne l'utilisez qu'une fois, vous n'avez pas besoin d'en faire une constante. Considérez cependant qu'une constante peut être documentée et apparaît dans Javadoc. Cela peut être important pour les valeurs de chaîne non triviales.
la source
Si vous voulez conserver cela (apporter des modifications non triviales), je pourrais envisager d'utiliser une sorte de génération de code basée sur des annotations (peut-être via CGLib ) ou même simplement un script qui écrit tout le code pour vous. Imaginez le nombre de fautes de frappe et d'erreurs qui pourraient s'introduire dans l'approche que vous envisagez ...
la source
object.getAddress().getCountry()
), ce qui est difficile à représenter avec des annotations. Les comparaisons de chaînes if / else ne sont pas jolies, mais elles sont rapides, flexibles, faciles à comprendre et faciles à tester.J'utiliserais toujours des constantes définies en haut de vos classes. Cela rend votre code plus facile à gérer car il est plus facile de voir ce qui peut être modifié ultérieurement (si nécessaire). Par exemple,
"first_name"
pourrait devenir"firstName"
ultérieurement.la source
Si votre dénomination est cohérente (aka
"some_whatever"
est toujours associée àgetSomeWhatever()
), vous pouvez utiliser la réflexion pour déterminer et exécuter la méthode get.la source
Je suppose que le traitement des annotations pourrait être la solution, même sans annotations. C'est la chose qui peut générer tout le code ennuyeux pour vous. L'inconvénient est que vous obtiendrez N classes générées pour N classes de modèle. Vous ne pouvez pas non plus ajouter quoi que ce soit à une classe existante, mais écrire quelque chose comme
une fois par classe ne devrait pas être un problème. Alternativement, vous pouvez écrire quelque chose comme
dans une superclasse commune.
Vous pouvez utiliser la réflexion au lieu du traitement des annotations pour la génération de code. L'inconvénient est que vous avez besoin de votre code pour compiler avant de pouvoir utiliser la réflexion dessus. Cela signifie que vous ne pouvez pas compter sur le code généré dans vos classes de modèle, sauf si vous générez des stubs.
J'envisagerais également l'utilisation directe de la réflexion. Bien sûr, la réflexion est lente, mais pourquoi est-elle lente? C'est parce qu'il doit faire tout ce que vous devez faire, par exemple, activer le nom du champ.
la source