É uma prática ruim armazenar certos valores como seqüências de caracteres?

19

É um título muito vago, mas não consegui pensar em uma maneira melhor de expressá-lo. Mas, apenas como exemplo, pense na direção em que um personagem de um jogo está se movendo. Parece meio errado usar uma corda e depois fazer coisas como if(character.direction == "left"). Parece-me que deixa muito espaço para erros tolos, como usar acidentalmente Leftou o que lquer que seja left. Minhas suspeitas estão corretas? Em caso afirmativo, qual é a maneira preferida de conseguir algo assim?

Cal7
fonte
10
você quer dizer, além de enums, se o seu idioma suportar isso?
Hoffmale
12
Você quer dizer Stringly Typed ?
precisa
Alguns idiomas não conseguem armazenar valores além de cadeias de caracteres, por exemplo bash,.
Mouviciel
não sei por que, mas lembrei-me do "define" em C. Você pode fazer coisas como: #define false true
linuxunil

Respostas:

28

Se o idioma que você está usando suporta o uso de enumerações, eu os usaria. Permite limitar o número de opções disponíveis para um determinado tipo. por exemplo, em Java:

public enum Direction {
    LEFT,
    RIGHT,
    UP,
    DOWN
}
Maybe_Factor
fonte
2
Esta resposta não contribui para a compreensão do problema do OP; Não vejo raciocínio aqui, apenas uma opinião limitada em escopo a idiomas com classe enumcomo java. Muitos idiomas (por exemplo, VBA) possuem enum, mas pode não ser a melhor opção, pois não possui a mesma prova de futuro. Veja minha resposta para uma discussão sobre por que enumapenas uma solução incompleta, geralmente quebradiça e específica de idioma.
sqykly
12

É uma prática terrível usar cadeias literais (ou números mágicos) no código.

As enumerações são boas ou, pelo menos, usam constantes (as enumerações são apenas um tipo de invólucro para uma ou mais constantes relacionadas).

const string LEFT = "left"
if (someThing == LEFT) { doStuff(); }

Essa mudança simples tem tantas vantagens que eu nem saberia por onde começar a explicá-las (pelo menos não sem mais café). Leia sobre números mágicos, é o mesmo conceito exato, aplicado apenas a um valor numérico em vez de um valor de string.

Aqui está uma referência rápida, tenho certeza que há centenas mais: /programming/47882/what-is-a-magic-number-and-why-is-it-bad

jleach
fonte
1
O problema que tenho com essa abordagem é que você recebe erros de digitação como --const string LEFT = "letf" - enquanto que se você trabalha com enumerações que são capturadas no momento da compilação.
Pieter B
@PieterB - Eu pensei que a pergunta dos OP era ampla o suficiente, e o exemplo de "left" era apenas um exemplo arbitrário - onde todos os casos não correspondiam a um enum. Concordo que, para um conjunto de instruções específicas, uma enumeração é a melhor escolha, mas minha resposta foi mais genérica na medida em que "se você a colocar em um literal, pelo menos a torne constante" (enum, é claro, sendo um tipo de constante)
jleach
3
Tive o prazer de trabalhar com um aplicativo que atribuiu os dias do fim de semana como aqueles dias cujo nome começa com um "s". Muito surpresos, eles ficaram com o "fato" de que, quando internacionalizaram o aplicativo, a França só teve um fim de semana de um dia.
Pieter B
4
Chame de microoptimização, mas alguns idiomas podem interpretar isso como uma comparação de valores e perder muito tempo verificando cada caractere na sequência. Ainda mais provável se você fizer o que o solicitante fez e comparar com a string codificada "esquerda". Se não for necessário que o valor constante seja uma string (ou seja, você não a imprime), seria melhor usar uma const int.
Devsman
4

Resposta curta: Sim, as strings não são ideais para nenhuma tarefa além de armazenar e acessar uma sequência de caracteres textuais e, mesmo que os bits subjacentes de uma abstração sejam strings, há benefícios em referenciá-los como variáveis ​​ou constantes .

Resposta longa: a maioria dos idiomas oferece tipos que estão mais próximos do domínio do seu problema e, mesmo que não, eles provavelmente possuem algum método pelo qual você pode definir leftcomo uma entidade diferente de right(etc etc). Transformar isso em uma string usando "left"é simplesmente perda da linguagem e da funcionalidade útil do IDE, como verificação de erro. Mesmo se você precisar usar

left = "left";

ou algo equivalente, ele tem vantagens em usar a string quando você se refere a ela em seu código. Por exemplo,

if (player.direction == Left)

seria detectado como um erro em tempo de compilação (na melhor das hipóteses, java e outros) ou seria sinalizado por qualquer IDE que tivesse seus bits como errado (na pior das hipóteses, básico e tal).

Além disso, ter a noção de leftuma entidade referenciável o ajudará a acomodar qualquer direção que você decidir seguir com o tipo de direção. Ao usar "left", a direção está comprometida em ser a String. Se você encontrar ou criar uma abstração melhor para o tipo, precisará procurar por todo o corpo do código, alterando cada instância de "left". Uma constante ou variável não exigirá nenhuma alteração se o tipo for elaborado.

O tipo que você realmente deseja é específico para o seu domínio. O que seu código está planejando fazer com o seu left? Talvez você queira espelhar o eixo x de uma textura ou sprite que esteja voltado para a esquerda ou avance; leftNesse caso, convém criar um objeto com uma propriedade ou método que reflita esse comportamento, com o rightobjeto tendo o resultado não espelhado oposto. Você pode fazer essa lógica em um objeto que representa os sprites ou texturas; nesse caso, novamente, você sofrerá o uso, em "left"vez de leftpelos motivos mencionados acima.

Em Java (e provavelmente em outras linguagens que ainda não conheço), enumé uma boa alternativa porque, em Java, enumé tão útil quanto final classem um conjunto finito de instâncias. Você pode definir comportamentos, se precisar deles, e pode mudar para uma classe aberta sem aborrecimentos fora do arquivo que declara o enum, mas muitos idiomas vêem isso enumcomo um tipo primitivo ou requerem sintaxe especial para usar. Isso vaza o enumcódigo para o código que não tem nada a ver com ele e pode precisar ser corrigido posteriormente. Certifique-se de entender o conceito de um idioma enumantes de considerar a opção.

sqykly
fonte
2

Você não especificou seu idioma, mas, para fornecer uma resposta genérica, use cadeias de caracteres quando realmente precisar do texto, para não representar algo. O exemplo que você deu, por exemplo, simplesmente não seria aceitável no software de produção.

Cada idioma possui vários tipos de dados básicos e você deve usar o mais apropriado para a tarefa. Para usar seu exemplo, você pode usar constantes numéricas para representar estados diferentes. Portanto, a esquerda poderia ter um valor zero e a direita seria um. Além do motivo mencionado, os valores numéricos ocupam menos espaço (memória) e é sempre mais rápido comparar números do que comparar várias seqüências de caracteres.

Como foi sugerido, use enumerações se o seu idioma permitir. No seu exemplo específico, é claramente a melhor escolha.

Nagev
fonte
É improvável que a velocidade e a memória sejam importantes. Dito isto, prefira enums ou constantes. As strings fazem mais sentido se os dados vierem de um formato de texto, por exemplo, XML, mas mesmo assim forem consistentes com todas as maiúsculas ou minúsculas. Ou, sempre converta , por exemplo. if (uppercase(foo) == "LEFT")
user949300
2
@ user949300 A conversão de cadeias de caracteres para todas as maiúsculas ou minúsculas também não é confiável. Existe a possibilidade de alguém decidir visitar outro local (ou expandir os negócios lá), como a Turquia , e quebrar as comparações ingênuas de cordas da caixa superior (ou caixa inferior).
8bittree
Preocupar-se com velocidade e memória é sempre uma boa prática, eles não são recursos infinitos. Embora seja aceitável sacrificá-lo conscientemente em prol da legibilidade ou de algum outro compromisso, o que não é o caso aqui. Mas não se importar com eles pode facilmente levar a aplicativos lentos ou inúteis.
Nagev
A comparação de strings provavelmente será 50 vezes mais lenta que a comparação de enums. Na maioria das vezes isso não importa. Mas se o seu código já estiver um pouco lento, essa diferença poderá torná-lo inaceitável. Mais importante, é claro, o fato de o compilador não poder ajudá-lo com erros de ortografia se você usar seqüências de caracteres.
precisa saber é o seguinte
1

Basta usar o tipo de dados que faz sentido na sua situação.

O uso do stringtipo como uma comunicação inter / intra-aplicativo subjacente não é inerentemente um problema. De fato, às vezes é preferível usar strings: se você tem uma API pública, pode ser desejável que os valores que entram e saem da API sejam legíveis por humanos. Isso facilita para as pessoas que usam sua API aprender e depurar.

O verdadeiro problema com o seu código está na repetição do valor.

Não faça isso:

if (direction == 'left') {
  goLeft();
}

Se você digitou um erro de digitação em um desses condicionais ou em outros usos de "esquerda" em algum lugar, talvez não seja possível executar efetivamente uma pesquisa em toda a base de código, porque você digitou errado!

Em vez disso, codifique contra uma enumeração ou uma constante - dependendo do suporte ao tipo de dados necessário no (s) idioma (s) que você está usando.

Esse meio LEFTdeve ser atribuído uma vez e apenas uma vez em seu aplicativo. E o restante do seu código deve aproveitar essas enumerações ou constantes:

const string LEFT = "left";

if (direction == LEFT) {
  goLeft();
}

Isso também permite que você altere mais facilmente o tipo de dados que você usa para suas direções posteriormente, se assim o desejar.

svidgen
fonte
1

É uma prática ruim?

Provavelmente sim, mas isso depende exatamente do que você está fazendo e também da linguagem de programação que você está usando.

No seu exemplo, podemos inferir que existe um conjunto pequeno e fixo de valores para sempre que uma direção pode tomar. Nesse caso, não há vantagens no uso de uma string e algumas desvantagens definidas. Para este exemplo:

  • Um enumtipo seria preferível, se sua linguagem de programação suportar isso.
  • Caso contrário, constantes inteiras nomeadas são o caminho a percorrer, com uma única definição para as constantes.

Mas a resposta pode ser diferente se o conjunto de valores for dinamicamente modificável ou precisar evoluir ao longo do tempo. Na maioria dos idiomas, alterar um enumtipo (por exemplo, para adicionar ou remover um valor) requer uma recompilação completa. (Por exemplo, a remoção de um valor de enum em Java quebra a compatibilidade binária.) E o mesmo se aplica às constantes inteiras nomeadas.

Em cenários como esse, outra solução pode ser necessária e o uso de strings é uma das opções. (E você pode combinar literais de seqüência de caracteres e constantes nomeadas ... se o cenário envolver um núcleo fixo com extensões dinâmicas.)


Se você estiver implementando em Java, character.direction == "left"é uma prática ruim por outro motivo. Você não deve usar ==para comparar cadeias, porque está testando identidades de objetos em vez de igualdade de cadeias. (Funcionaria se você pudesse garantir que todas as instâncias da "left"cadeia de caracteres foram internadas, mas isso requer análise de todo o aplicativo.)

Stephen C
fonte
1
O que parece fixo para sempre muitas vezes acaba não sendo tão fixo. Quatro direções podem, por exemplo, tornar-se oito.
Jimmy T.
@JimmyT. - Isso depende do contexto. Por exemplo, em um jogo, alterar o número de direções que um personagem pode mover de 4 para 8 implicaria uma revisão completa das regras do jogo e o código que implementa as regras. Usar Stringpara representar as direções faria quase zero diferença para a quantidade de trabalho envolvido para fazer as alterações. Uma abordagem mais sensata é assumir que o número de direções não mudará e reconhecer que você teria muito trabalho a fazer de qualquer maneira se as regras do jogo mudassem tão fundamentalmente.
Stephen C
@ JimmyT - Concordo totalmente que já vi isso acontecer muitas vezes, você também recebe os desenvolvedores que redefinem a string, por exemplo, product = "Option" se torna product = "Option_or_Future" degradando totalmente o significado do código.
Chris Milburn
-3

Como sugerido, você deve usar Enums. No entanto, apenas usar o Enum como um substituto para o Strigns não é suficiente IMHO. No seu exemplo particular, a velocidade do jogador deve ser realmente um vetor por meio da física:

class Vector {
  final double x;
  final double y;
}

Esse vetor deve ser usado para atualizar a posição do jogador a cada tick.

Você pode combinar isso com uma enumeração para maior legibilidade:

enum Direction {
  UP(new Vector(0, 1)),
  RIGHT(new Vector(1, 0)),
  DOWN(new Vector(0, -1)),
  LEFT(new Vector(-1, 0));

  private Vector direction;

  Direction(Vector v) {
    this.direction = v;
  }

  public Vector getVector() { return this.direction; }
}
marstato
fonte
4
-1 Você está indo longe demais no exemplo que ele dá.
Pieter B