Estamos implementando um adaptador para o Jaxen (uma biblioteca XPath para Java) que nos permite usar o XPath para acessar o modelo de dados de nosso aplicativo.
Isso é feito implementando classes que mapeiam seqüências de caracteres (passadas do Jaxen para nós) em elementos do nosso modelo de dados. Estimamos que precisaremos de cerca de 100 classes com mais de 1000 comparações de strings no total.
Eu acho que a melhor maneira de fazer isso é simples declarações if / else com as strings escritas diretamente no código - em vez de definir cada strings como uma constante. Por exemplo:
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();
...
No entanto, sempre fui ensinado que não devemos incorporar valores de string diretamente no código, mas criar constantes em vez disso. Isso seria algo como isto:
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();
...
Nesse caso, acho que é uma má ideia. A constante será usada apenas uma vez no getNode()
método. Usar as strings diretamente é tão fácil de ler e entender quanto usar constantes e nos poupa a escrever pelo menos mil linhas de código.
Existe alguma razão para definir constantes de string para um único uso? Ou é aceitável usar seqüências de caracteres diretamente?
PS. Antes que alguém sugira o uso de enumerações, prototipamos isso, mas a conversão de enumerações é 15 vezes mais lenta que a simples comparação de cadeias, para que não seja considerada.
Conclusão: As respostas abaixo expandiram o escopo desta pergunta além de apenas constantes de string, então eu tenho duas conclusões:
- Provavelmente, não há problema em usar as seqüências diretamente, em vez de constantes, neste cenário, mas
- Existem maneiras de evitar o uso de strings, o que pode ser melhor.
Então, eu vou tentar a técnica de invólucro que evita seqüências de caracteres completamente. Infelizmente, não podemos usar a instrução switch de cadeia porque ainda não estamos no Java 7. Em última análise, porém, acho que a melhor resposta para nós é tentar cada técnica e avaliar seu desempenho. A realidade é que, se uma técnica for claramente mais rápida, provavelmente a escolheremos, independentemente de sua beleza ou adesão à convenção.
fonte
switch
rótulos. Use um switch em vez deif
cascatas.Respostas:
Tente isso. A reflexão inicial é certamente cara, mas se você a usar muitas vezes, o que eu acho que você usará, essa certamente será uma solução melhor para o que você está propondo. Não gosto de usar reflexão, mas me vejo usando quando não gosto da alternativa à reflexão. Eu acho que isso poupará muita dor de cabeça à sua equipe, mas você deve passar o nome do método (em minúsculas).
Em outras palavras, em vez de passar "nome", você passaria "nome completo" porque o nome do método get é "getFullName ()".
Se você precisar acessar os dados contidos nos membros do contato, considere criar uma classe de wrapper para o contato que possua todos os métodos para acessar qualquer informação necessária. Isso também seria útil para garantir que os nomes dos campos de acesso sempre permaneçam os mesmos (ou seja, se a classe do wrapper tiver getFullName () e você chamar com fullname, ele sempre funcionará mesmo que o getFullName () do contato tenha sido renomeado - ele causaria um erro de compilação antes de permitir isso).
Essa solução me salvou várias vezes, ou seja, quando eu queria ter uma única representação de dados para usar em tabelas de dados jsf e quando esses dados precisavam ser exportados para um relatório usando jasper (que não lida bem com acessadores de objetos complicados na minha experiência) .
fonte
.invoke()
, porque elimina completamente as constantes de string. Não gosto muito da reflexão em tempo de execução para configurar o mapa, embora talvez esteja executandogetMethodMapping()
em umstatic
bloco esteja OK para que aconteça na inicialização, em vez de quando o sistema estiver em execução.Se possível, use o Java 7, que permite usar Strings em
switch
instruções.Em http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
Não medi, mas acredito que as instruções switch são compiladas em uma tabela de salto em vez de uma longa lista de comparações. Isso deve ser ainda mais rápido.
Em relação à sua pergunta real: Se você a usar apenas uma vez , não será necessário transformá-la em uma constante. Considere, no entanto, que uma constante pode ser documentada e exibida em Javadoc. Isso pode ser importante para valores de sequência não triviais.
fonte
Se você deseja manter isso (faça qualquer tipo de alteração não trivial), eu poderia considerar usar algum tipo de geração de código orientado a anotações (talvez via CGLib ) ou até mesmo apenas um script que escreva todo o código para você. Imagine o número de erros de digitação e erros que podem surgir com a abordagem que você está considerando ...
fonte
object.getAddress().getCountry()
)), o que é difícil de representar com anotações. As comparações de strings if / else não são bonitas, mas são rápidas, flexíveis, fáceis de entender e fáceis de testar na unidade.Eu ainda usaria constantes definidas no topo de suas aulas. Isso torna seu código mais sustentável, pois é mais fácil ver o que pode ser alterado posteriormente (se necessário). Por exemplo,
"first_name"
pode se tornar"firstName"
em algum momento posterior.fonte
Se sua nomeação for consistente (também conhecida como
"some_whatever"
sempre é mapeadagetSomeWhatever()
), você poderá usar a reflexão para determinar e executar o método get.fonte
Eu acho que o processamento de anotações pode ser a solução, mesmo sem anotações. É o que pode gerar todo o código chato para você. A desvantagem é que você receberá N classes geradas para N classes de modelo. Você também não pode adicionar nada a uma classe existente, mas escrevendo algo como
uma vez por aula não deve ser um problema. Como alternativa, você pode escrever algo como
em uma superclasse comum.
Você pode usar reflexão em vez de processamento de anotação para geração de código. A desvantagem é que você precisa que seu código seja compilado antes de poder refletir sobre ele. Isso significa que você não pode confiar no código gerado em suas classes de modelo, a menos que gere alguns stubs.
Eu também consideraria o uso direto da reflexão. Claro, a reflexão é lenta, mas por que é lenta? É porque ele precisa fazer todas as coisas necessárias, por exemplo, ativar o nome do campo.
fonte