Estou olhando alguns projetos Java de software livre para entrar em Java e observei que muitos deles têm algum tipo de interface de 'constantes'.
Por exemplo, processing.org tem uma interface chamada PConstants.java , e a maioria das outras classes principais implementam essa interface. A interface está repleta de membros estáticos. Há um motivo para essa abordagem ou isso é considerado uma prática inadequada? Por que não usar enums onde faz sentido ou uma classe estática?
Acho estranho usar uma interface para permitir algum tipo de pseudo 'variáveis globais'.
public interface PConstants {
// LOTS OF static fields...
static public final int SHINE = 31;
// emissive (by default kept black)
static public final int ER = 32;
static public final int EG = 33;
static public final int EB = 34;
// has this vertex been lit yet
static public final int BEEN_LIT = 35;
static public final int VERTEX_FIELD_COUNT = 36;
// renderers known to processing.core
static final String P2D = "processing.core.PGraphics2D";
static final String P3D = "processing.core.PGraphics3D";
static final String JAVA2D = "processing.core.PGraphicsJava2D";
static final String OPENGL = "processing.opengl.PGraphicsOpenGL";
static final String PDF = "processing.pdf.PGraphicsPDF";
static final String DXF = "processing.dxf.RawDXF";
// platform IDs for PApplet.platform
static final int OTHER = 0;
static final int WINDOWS = 1;
static final int MACOSX = 2;
static final int LINUX = 3;
static final String[] platformNames = {
"other", "windows", "macosx", "linux"
};
// and on and on
}
static final
não é necessário, é redundante para uma interface.platformNames
pode serpublic
,static
efinal
, mas definitivamente não é uma constante. A única matriz constante é uma com comprimento zero.static final
não é necessariamente redundante. Um campo de classe ou interface com apenas afinal
palavra - chave criaria instâncias separadas desse campo à medida que você cria objetos da classe ou interface. Usarstatic final
faria com que cada objeto compartilhasse um local de memória para aquele campo. Em outras palavras, se uma classe MyClass tivesse um campofinal String str = "Hello";
, para N instâncias de MyClass, haveria N instâncias do campo str na memória. Adicionar astatic
palavra - chave resultaria em apenas 1 instância.Respostas:
Geralmente é considerada uma prática ruim. O problema é que as constantes são parte da "interface" pública (na falta de uma palavra melhor) da classe de implementação. Isso significa que a classe de implementação está publicando todos esses valores em classes externas, mesmo quando eles são necessários apenas internamente. As constantes proliferam em todo o código. Um exemplo é a interface SwingConstants no Swing, que é implementada por dezenas de classes que "reexportam" todas as suas constantes (mesmo as que não usam) como suas próprias.
Mas não acredite apenas na minha palavra, Josh Bloch também diz que é ruim:
Um enum pode ser uma abordagem melhor. Ou você pode simplesmente colocar as constantes como campos estáticos públicos em uma classe que não pode ser instanciada. Isso permite que outra classe os acesse sem poluir sua própria API.
fonte
Em vez de implementar uma "interface de constantes", em Java 1.5+, você pode usar importações estáticas para importar as constantes / métodos estáticos de outra classe / interface:
Isso evita a feiura de fazer suas classes implementarem interfaces sem funcionalidade.
Quanto à prática de ter uma aula apenas para armazenar constantes, acho que às vezes é necessário. Existem certas constantes que simplesmente não têm um lugar natural em uma classe, então é melhor colocá-las em um lugar "neutro".
Mas em vez de usar uma interface, use uma classe final com um construtor privado. (Tornando impossível instanciar ou criar uma subclasse da classe, enviando uma mensagem forte de que ela não contém funcionalidade / dados não estáticos.)
Por exemplo:
fonte
Não pretendo estar certo, mas vamos ver este pequeno exemplo:
ToyotaCar não sabe nada sobre FordCar e FordCar não sabe sobre ToyotaCar. princípio CarConstants deve ser alterado, mas ...
As constantes não devem ser alteradas, porque a roda é redonda e a roda é mecânica, mas ... No futuro, os engenheiros de pesquisa da Toyota inventaram o motor eletrônico e as rodas planas! Vamos ver nossa nova interface
e agora podemos mudar nossa abstração:
para
E agora, se precisarmos mudar o valor central do MOTOR ou RODA, podemos mudar a Interface do ToyotaCar no nível de abstração, sem tocar nas implementações
NÃO É SEGURO, eu sei, mas ainda quero saber o que você pensa sobre isso
fonte
Há muito ódio por esse padrão em Java. No entanto, uma interface de constantes estáticas às vezes tem valor. Você precisa basicamente cumprir as seguintes condições:
Os conceitos fazem parte da interface pública de várias classes.
Seus valores podem mudar em versões futuras.
Por exemplo, suponha que você esteja escrevendo uma extensão para uma linguagem de consulta hipotética. Nesta extensão, você vai expandir a sintaxe da linguagem com algumas novas operações, que são suportadas por um índice. Por exemplo, você terá um R-Tree com suporte a consultas geoespaciais.
Então, você escreve uma interface pública com a constante estática:
Mais tarde, um novo desenvolvedor pensa que precisa construir um índice melhor, então ele vem e constrói uma implementação R *. Ao implementar esta interface em sua nova árvore, ele garante que os diferentes índices terão sintaxe idêntica na linguagem de consulta. Além disso, se mais tarde você decidiu que "nearTo" era um nome confuso, poderia alterá-lo para "withinDistanceInKm" e saber que a nova sintaxe seria respeitada por todas as implementações de índice.
PS: A inspiração para este exemplo é tirada do código espacial Neo4j.
fonte
Dada a vantagem da retrospectiva, podemos ver que o Java está corrompido de várias maneiras. Uma das principais falhas do Java é a restrição das interfaces a métodos abstratos e campos finais estáticos. Linguagens OO mais novas e sofisticadas, como Scala, classificam as interfaces por traços que podem (e normalmente incluem) métodos concretos, que podem ter aridade zero (constantes!). Para uma exposição sobre traços como unidades de comportamento combinável, consulte http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf . Para uma breve descrição de como as características em Scala se comparam a interfaces em Java, consulte http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-5. No contexto do ensino de design OO, regras simplistas como afirmar que as interfaces nunca devem incluir campos estáticos são bobas. Muitas características incluem naturalmente constantes e essas constantes são apropriadamente parte da "interface" pública suportada pela característica. Ao escrever código Java, não há uma maneira limpa e elegante de representar características, mas o uso de campos finais estáticos nas interfaces costuma ser parte de uma boa solução alternativa.
fonte
De acordo com a especificação JVM, os campos e métodos em uma Interface podem ter apenas Public, Static, Final e Abstract. Ref de Inside Java VM
Por padrão, todos os métodos na interface são abstratos, mesmo que você não tenha mencionado isso explicitamente.
As interfaces destinam-se a fornecer apenas especificações. Ele não pode conter nenhuma implementação. Portanto, para evitar a implementação de classes para alterar a especificação, ela é finalizada. Como a Interface não pode ser instanciada, eles se tornam estáticos para acessar o campo usando o nome da interface.
fonte
Não tenho reputação suficiente para fazer um comentário a Pleerock, portanto, devo criar uma resposta. Lamento por isso, mas ele fez um grande esforço e gostaria de lhe responder.
Pleerock, você criou o exemplo perfeito para mostrar por que essas constantes devem ser independentes de interfaces e independentes de herança. Para o cliente do aplicativo não é importante que haja uma diferença técnica entre aquelas implementações de carros. São iguais para o cliente, apenas carros. Então, o cliente quer olhar para eles dessa perspectiva, que é uma interface como I_Somecar. Ao longo do aplicativo, o cliente usará apenas uma perspectiva e não diferentes para cada marca de carro diferente.
Se um cliente quiser comparar carros antes de comprar, ele pode ter um método como este:
Uma interface é um contrato sobre comportamento e mostra diferentes objetos de uma perspectiva. Da maneira como você o projeta, cada marca de automóveis terá sua própria linha de herança. Embora seja na realidade bastante correto, porque os carros podem ser tão diferentes que podem ser como comparar tipos de objetos completamente diferentes, no final há uma escolha entre carros diferentes. E essa é a perspectiva da interface que todas as marcas devem compartilhar. A escolha das constantes não deve tornar isso impossível. Por favor, considere a resposta de Zarkonnen.
fonte
Isso veio de um tempo antes de o Java 1.5 existir e trazer enums para nós. Antes disso, não havia uma boa maneira de definir um conjunto de constantes ou valores restritos.
Isso ainda é usado, na maioria das vezes, seja para compatibilidade com versões anteriores ou devido à quantidade de refatoração necessária para se livrar, em muitos projetos.
fonte