Usando classes públicas aninhadas para organizar constantes

21

Estou trabalhando em um aplicativo com muitas constantes. Na última revisão de código, constatou-se que as constantes estão muito dispersas e devem ser organizadas em um único arquivo de constantes "principais". A discordância é sobre como organizá-los. A maioria considera que o uso do nome constante deve ser bom o suficiente, mas isso levará a um código parecido com este:

public static final String CREDITCARD_ACTION_SUBMITDATA = "6767";
public static final String CREDITCARD_UIFIELDID_CARDHOLDER_NAME = "3959854";
public static final String CREDITCARD_UIFIELDID_EXPIRY_MONTH = "3524";
public static final String CREDITCARD_UIFIELDID_ACCOUNT_ID = "3524";
...
public static final String BANKPAYMENT_UIFIELDID_ACCOUNT_ID = "9987";

Acho esse tipo de convenção de nomenclatura complicado. Eu pensei que poderia ser mais fácil usar a classe aninhada pública e ter algo como isto:

public class IntegrationSystemConstants
{
    public class CreditCard
    {
        public static final String UI_EXPIRY_MONTH = "3524";
        public static final String UI_ACCOUNT_ID = "3524";
        ...
    }
    public class BankAccount
    {
        public static final String UI_ACCOUNT_ID = "9987";
        ...
    }
}

Essa ideia não foi bem recebida porque era "muito complicada" (não obtive muitos detalhes sobre por que isso pode ser muito complicado). Eu acho que isso cria uma divisão melhor entre grupos de constantes relacionadas e o preenchimento automático facilita a localização também. Eu nunca vi isso feito, então estou me perguntando se essa é uma prática aceita ou se há melhores razões para que isso não deva ser feito.

FrustratedWithFormsDesigner
fonte
1
Eu gosto bastante da ideia. Eu me vi fazendo algo semelhante em C ++ quando queria escopo e comportamento em estilo de C #, mas com valores significativos (acho que a idéia surgiu porque eu me acostumei a usar classes de casos no lugar de enumerações em Scala). Concedido, este foi um projeto pessoal por diversão, e não um esforço de equipe.
KChaloux

Respostas:

13

Não concordo com nenhuma das duas propostas.

As constantes devem estar em suas classes pertinentes , não em uma classe todo-constante em qualquer uma das duas formas propostas.

Não deve haver classes / interfaces somente constantes.

Uma classe CreditCard(não uma classe interna) deve existir. Esta classe / interface possui métodos relativos a cartões de crédito, bem como as constantes UI_EXPIRY_MONTHe UI_ACCOUNT_ID.

Deve existir uma classe / interface BankAccount(não uma classe interna). Essa classe / interface possui métodos relativos a contas bancárias e também constantes UI_ACCOUNT_ID.

Por exemplo, na API Java, toda classe / interface tem suas constantes. Eles não estão em uma classe / interface de Constantes com centenas de constantes, agrupadas em classes internas ou não.

Por exemplo, essas constantes pertinentes aos conjuntos de resultados estão na interface ResultSet:

static int  CLOSE_CURSORS_AT_COMMIT 
static int  CONCUR_READ_ONLY 
static int  CONCUR_UPDATABLE 
static int  FETCH_FORWARD 
static int  FETCH_REVERSE 
static int  FETCH_UNKNOWN 
static int  HOLD_CURSORS_OVER_COMMIT 
static int  TYPE_FORWARD_ONLY 
static int  TYPE_SCROLL_INSENSITIVE 
static int  TYPE_SCROLL_SENSITIVE 

Essa interface possui assinaturas de método relativas aos conjuntos de resultados e as classes de implementação implementam esse comportamento. Eles não são meros detentores de constantes.

Essas constantes pertinentes às ações da interface do usuário estão na interface javax.swing.Action:

static String   ACCELERATOR_KEY 
static String   ACTION_COMMAND_KEY 
static String   DEFAULT 
static String   LONG_DESCRIPTION 
static String   MNEMONIC_KEY 
static String   NAME 
static String   SHORT_DESCRIPTION 
static String   SMALL_ICON 

As classes de implementação têm comportamento em relação às ações da interface do usuário, não são meros detentores constantes.

Conheço pelo menos uma interface de "constantes" ( SwingConstants) sem métodos, mas ela não possui centenas de constantes, apenas algumas, e todas estão relacionadas às direções e posições dos elementos da interface do usuário:

static int  BOTTOM 
static int  CENTER 
static int  EAST 
static int  HORIZONTAL 
static int  LEADING 
static int  LEFT 
static int  NEXT 
static int  NORTH 
static int  NORTH_EAST 
static int  NORTH_WEST 
static int  PREVIOUS 
static int  RIGHT 
static int  SOUTH 
static int  SOUTH_EAST 
static int  SOUTH_WEST 
static int  TOP 
static int  TRAILING 
static int  VERTICAL 
static int  WEST 

Penso que apenas classes constantes não são um bom design de OO.

Tulains Córdova
fonte
1
Embora eu concorde que constantes apenas classes sejam, na maioria dos casos, um sinal de mau design, há usos legítimos. Por exemplo, a constante nem sempre "pertence" a uma classe específica. As chaves para extras de intenção na programação do Android são um exemplo concreto.
precisa saber é o seguinte
1
+1, mas as constantes da interface do usuário provavelmente não devem estar em modelos de negócios como BankAccount. Eles pertencem a alguma classe de interface do usuário.
kevin Cline
10

descobriu-se que as constantes são muito dispersas e devem ser organizadas em um único arquivo de constantes "principais".

Esta é a solução 100% errada para o problema das constantes serem "difíceis de encontrar". É um erro fundamental (infelizmente comumente cometido por programadores) agrupar coisas por critérios técnicos, como constantes, enumerações ou interfaces.

Exceto pelas arquiteturas de camada, as coisas devem ser agrupadas por seu domínio e constantes ainda mais, pois são elementos de nível muito baixo. As constantes devem fazer parte das classes ou interfaces que as usam como parte de sua API. Se você não conseguir encontrar um lugar natural para morar, precisará limpar o design da API.

Além disso, um único arquivo de constantes enormes reduz a velocidade de desenvolvimento em Java, porque as constantes são incorporadas às classes que os usam em tempo de compilação; portanto, qualquer alteração força a recompilação de todos esses arquivos e tudo o que depende deles. Se você tiver um arquivo com constantes que são usadas em todos os lugares, perderá amplamente o benefício da compilação incremental: observe o Eclipse travar por 15 minutos, pois recompila todo o projeto para cada alteração nesse arquivo. E como esse arquivo contém todas as constantes usadas em qualquer lugar, você será alterado com bastante frequência. Sim, estou falando por experiência pessoal.

Michael Borgwardt
fonte
Eu não estava ciente do impacto potencial no ambiente de desenvolvimento e acho que a abordagem de classe aninhada não ajudará muito nisso, certo?
FrustratedWithFormsDesigner
1
@FrustratedWithFormsDesigner: depende de quanto esforço o mecanismo de compilação incremental gasta na modelagem de dependências.
Michael Borgwardt
9

Você está certo. Sua sugestão permite que um programador import static Constants.BankAccount.*elimine inúmeras repetições de 'BANKACCOUNT_'. A concatenação é um mau substituto para o escopo real. Dito isto, não tenho muita esperança de que você mude a cultura da equipe. Eles têm noção de práticas adequadas e provavelmente não mudarão, mesmo que você mostre a eles 100 especialistas que dizem estar errados.

Também estou me perguntando por que você tem um único arquivo 'Constantes'. Essa é uma prática muito ruim, a menos que essas constantes estejam relacionadas de alguma forma e sejam muito estáveis. Mais tipicamente, torna-se um tipo de classe de pia de cozinha que muda constantemente e depende de tudo.

Kevin Cline
fonte
Atualmente, temos um arquivo de constantes que contém a maioria das constantes de ID do campo da interface do usuário e alguns outros arquivos de constantes específicos do subprojeto. Mas agora, as constantes específicas dos subprojetos precisam ser usadas por outros subprojetos relacionados, e foi isso que levou a ideia a mesclar todas elas em um arquivo de constantes "principais". O que é melhor do que agora, porque às vezes nem sei quais arquivos de constantes referenciam um valor, e alguém criou uma duplicata de uma constante porque não conseguiu encontrá-la no arquivo de constantes de um subprojeto diferente.
FrustratedWithFormsDesigner
8
Uma classe de constantes que muda constantemente ... há algo de zen ali, se você cavar o suficiente.
KChaloux 26/10/12
2
@FrustratedWithFormsDesigner: IDs de campos da interface do usuário? Não sabe onde encontrar um valor? Parece uma enorme pilha de WTF. Você tem minha simpatia.
kevin Cline
6

Ambas as abordagens funcionam, e é isso que é importante no final do dia.

Dito isso, sua abordagem é comum o suficiente para ser considerada um padrão ou, com mais precisão, uma melhoria suficientemente boa sobre o antipadrão da interface constante . Não vejo o que é complicado, mas é uma discussão que você deve ter com sua equipe.

yannis
fonte
Para uma lista suficientemente longa de constantes, eu preferiria interfaces constantes do que tê-las todas na mesma classe. É perigosamente possível escolher o errado da conclusão automática. Claro, isso depende de quanto tempo é tempo suficiente :)
Goran Jovic
1
@GoranJovic Bem, todo anti-padrão é útil de alguma forma (ou pelo menos conveniente), não se tornaria um padrão se não fosse.
26912 yannis
1

Um dos desafios da longa lista de constantes é encontrar a constante "correta" a ser usada. Invariavelmente, alguém insere uma constante no final da linha em vez de adicioná-la ao grupo ao qual pertencia.

O que traz outro ponto a ser discutido com sua equipe - já existe uma categorização de fato das constantes através de seus nomes. Portanto, não deve ser uma grande mudança para eles do estado atual para o que você está propondo. O uso do preenchimento automático facilita ainda mais as pesquisas constantes.

De qualquer forma, sua sugestão ajuda a desencorajar o uso da constante "errada", mesmo que ela se encaixe em uma situação específica. Ao agrupar as constantes em uma classe representativa, isso incentivará os desenvolvedores a pensarem se deveriam usá-la. Por exemplo, se eu CreditCard.SomeConstantusar para uso geral, realmente me pergunto por que não existe um General.SomeConstantpara essa situação.

Estive em projetos com quantidades monstruosas de constantes e preferia ter o método que você está sugerindo. É mais limpo, mais direto e ajuda a evitar o uso inadvertido.


fonte
1

Faço isso ocasionalmente (em C #), principalmente se precisar programar / analisar uma estrutura XML conhecida e fixa ou algo aninhado e pesado de forma semelhante ... por exemplo, um analisador de bloco de configuração personalizado.

Eu construo uma estrutura de classe aninhada que corresponde à estrutura hierárquica do XML com os nomes de classe correspondentes aos elementos que contêm uma propriedade const string "ElementName" e uma propriedade semelhante correspondente a cada Atributo (se houver).

Isso facilita muito a programação no Xml correspondente.

Ed Hastings
fonte