Respostas:
Colocar membros estáticos em uma interface (e implementar essa interface) é uma prática ruim e existe até um nome para ela, o Antipadrão da Interface Constante , consulte Java Efetivo , Item 17:
O padrão de interface constante é um mau uso de interfaces . O fato de uma classe usar algumas constantes internamente é um detalhe de implementação. A implementação de uma interface constante faz com que esses detalhes da implementação vazem para a API exportada da classe. Não tem importância para os usuários de uma classe que a classe implemente uma interface constante. De fato, pode até confundi-los. Pior, representa um comprometimento: se em uma versão futura a classe for modificada para não precisar mais usar as constantes, ainda deverá implementar a interface para garantir a compatibilidade binária. Se uma classe não final implementa uma interface constante, todas as suas subclasses terão seus espaços de nomes poluídos pelas constantes na interface.
Existem várias interfaces constantes nas bibliotecas da plataforma java, como
java.io.ObjectStreamConstants
. Essas interfaces devem ser consideradas anomalias e não devem ser emuladas.
Para evitar algumas armadilhas da interface constante (porque você não pode impedir as pessoas de implementá-la), uma classe apropriada com um construtor privado deve ser preferida (exemplo emprestado da Wikipedia ):
public final class Constants {
private Constants() {
// restrict instantiation
}
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
E para acessar as constantes sem precisar qualificá-las completamente (ou seja, sem precisar prefixá-las com o nome da classe), use uma importação estática (desde o Java 5):
import static Constants.PLANCK_CONSTANT;
import static Constants.PI;
public class Calculations {
public double getReducedPlanckConstant() {
return PLANCK_CONSTANT / (2 * PI);
}
}
" O padrão de interface constante é um mau uso de interfaces "
Quem inventou essa hipótese, por mais que seja um guru, inventou-a com base na necessidade de continuar implementando maus hábitos e práticas com eficiência. A hipótese é baseada na promoção da validade de maus hábitos de design de software.
Escrevi uma resposta contra essa hipótese aqui: Qual é a melhor maneira de implementar constantes em Java? explicando a falta de fundamento dessa hipótese.
Por 10 anos, essa pergunta permaneceu em aberto, até que ela foi encerrada dentro de duas horas depois de eu ter postado minhas razões para desajustar essa hipótese, expondo, assim, a INCORPORATIVA para o debate daqueles que se apegam a essa hipótese equivocada.
Estes são os pontos que expressei contra a hipótese
A base para sustentar essa hipótese é a necessidade de métodos e regras RESTRITIVAS para lidar com os efeitos de maus hábitos e metodologias de software.
Os proponentes do sentimento " O padrão de interface constante é um mau uso de interfaces" são incapazes de fornecer outros motivos além daqueles causados pela necessidade de lidar com os efeitos desses maus hábitos e práticas.
Resolva a questão fundamental.
E então, por que não fazer pleno uso e explorar todos os recursos de linguagem da estrutura de linguagem Java para sua própria conveniência. Não são necessários revestimentos. Por que inventar regras para impedir seu estilo de vida ineficaz para discriminar e incriminar estilos de vida mais eficazes?
é organização da informação. As informações que mediam o processo e o comportamento dessas informações devem primeiro ser entendidas, juntamente com as chamadas regras de negócios - antes de projetar ou complementar as soluções do processo. Esse método de organização da informação foi chamado de normalização de dados algumas décadas atrás.
Somente a engenharia de uma solução é possível porque alinhar a granularidade e a modularidade dos componentes de uma solução com a granularidade e modularidade dos componentes da informação é a estratégia ideal.
Existem dois ou três obstáculos significativos na organização da informação.
A falta de percepção para a necessidade de modelo de dados "normalização".
As declarações da EF Codd sobre normalização de dados são falhas, defeituosas e ambíguas.
A moda passageira mais recente disfarçada de engenharia ágil é a noção equivocada de que não se deve planejar e condicionar a organização dos módulos adiante, porque você pode refatorar à medida que avança. A refatoração e a mudança contínua sem ser impedido por descobertas futuras são usadas como desculpa. As descobertas essenciais do comportamento das informações do processo são, então, usando truques contábeis para atrasar lucros e ativos, pelo que o conhecimento essencial e seu tratamento são considerados desnecessários agora.
Não crie regras nem faça nenhuma fatwa contra isso só porque você ama seus hábitos de programação ad-hoc hit-and-run.
Não proíba a posse de armas pelo motivo de que existem pessoas que não sabem como lidar com armas ou têm tendência a abusar de armas.
Se as regras que você cria destinam-se a programar iniciantes incapazes de codificar profissionalmente e que você se inclui entre elas, diga-o - não declare sua fatwa como aplicável a modelos de dados normalizados adequadamente.
Não ligo para o que as intenções originais dos pais fundadores tinham com a Constituição dos EUA. Não me importo com as intenções não escritas não escritas. Preocupo-me apenas com o que é literariamente codificado na Constituição escrita e como posso explorá-los para o funcionamento efetivo da sociedade.
Eu me preocupo apenas com o que as especificações da linguagem / plataforma Java me permitem e pretendo explorá-las ao máximo para me proporcionar um meio de expressar minhas soluções de software de maneira eficiente e eficaz. Não são necessárias jaquetas.
Requer escrever código extra para mapear o parâmetro para o valor. O fato de os fundadores do Java não fornecerem mapeamento de valor de parâmetro sem que você escreva que o código de mapeamento demonstra que as constantes Enum são o uso não intencional da linguagem Java.
Especialmente porque você não é incentivado a normalizar e a componentes seus parâmetros, haveria uma falsa impressão de que os parâmetros misturados em uma bolsa Enum pertencem à mesma dimensão.
Não esqueça disso. Se você projetou e normalizou seu modelo de dados e eles incluem constantes, essas constantes são contratos. Se você não normalizou seu modelo de dados, deve seguir o exemplo de como praticar a codificação restritiva para lidar com esse mau hábito.
Portanto, as interfaces são uma maneira perfeita de implementar o contrato de constantes.
Sim. Qualquer um poderia inadvertidamente implementar qualquer interface inadvertidamente. Nada atrapalhará esses programadores inadvertidos.
Não faça decretos restritivos para proteger práticas ruins presumidas que causam vazamento de parâmetros não contratados / perdidos na API. Resolva a questão fundamental, em vez de culpar as constantes da interface.
Um programador normal e EFICAZ em funcionamento normal não está lá para provar quanto tempo ela pode ficar embaixo da água, até onde ela poderia caminhar sob calor escaldante ou tempestades úmidas. Ela deve usar uma ferramenta eficiente, como um carro, ônibus ou pelo menos uma bicicleta, para levá-la a 16 quilômetros para trabalhar todos os dias.
Não imponha restrições a outros programadores apenas porque você tem uma obsessão esotérica pelo ascetismo com a programação sem IDE.
OSGI é esse quadro. E também o decreto contra as constantes da interface.
As constantes de interface são uma maneira eficaz e eficiente de colocar no Contrato componentes bem projetados e normalizados de um modelo de dados.
As constantes de interface em uma interface privada nomeada apropriadamente aninhada em um arquivo de classe também são boas práticas para agrupar todas as suas constantes privadas, em vez de dispersá-las por todo o arquivo.
Me deparei com essa pergunta antiga várias vezes agora e a resposta aceita ainda me confunde. Depois de muito pensar, acho que essa questão pode ser mais esclarecida.
Basta compará-los:
public final class Constants {
private Constants() {
// restrict instantiation
}
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
vs
public interface Constants {
public double PI = 3.14159;
public double PLANCK_CONSTANT = 6.62606896e-34;
}
Mesmo uso. Muito menos código.
Acho que a resposta de @Pascal Thivent tem a ênfase errada, aqui está minha versão:
Colocar membros estáticos em uma interface ( e implementar essa interface ) é uma prática ruim.
A citação de Effective Java pressupõe que a interface constante esteja sendo implementada por outros, o que eu acho que não deve (e não vai) acontecer.
Quando você cria uma interface constante chamada algo como Constants
, ela não deve ser implementada por ninguém. (embora tecnicamente possível, que é o único problema aqui)
A biblioteca padrão não pode permitir qualquer uso indevido possível do design, portanto você não verá nenhum lá.
No entanto , para projetos diárias de desenvolvedores normais, usando a interface constantes é muito mais fácil porque você não precisa se preocupar com static
, final
, empty constructor
, etc, e ele não irá causar qualquer problema de design ruim. A única desvantagem em que consigo pensar é que ele ainda tem o nome de "interface", mas nada além disso.
No final, acho que todo mundo está apenas citando livros e dando opiniões e justificativas para suas posições. Sem exceção para mim. Talvez a decisão ainda seja da responsabilidade dos desenvolvedores de cada projeto. Vá em frente para usá-lo, se você se sentir confortável. O melhor que podemos fazer é torná-lo consistente ao longo do projeto .
public
também pode ser omitido, pois é uma interface, simplificando o double PI = 3.14159;
uso de Constants.PI
não precisa da classe que usa isso para implementar a Constants
interface! Eu acho que a abordagem da interface é muito mais limpa em termos de uso, IMHO
Joshua Bloch, "Java Efetivo - Guia da Linguagem de Programação":
O padrão de interface constante é um mau uso de interfaces. O fato de uma classe usar algumas constantes internamente é um detalhe de implementação. A implementação de uma interface constante faz com que esses detalhes da implementação vazem para a API exportada da classe. Não tem importância para os usuários de uma classe que a classe implemente uma interface constante. De fato, pode até confundi-los. Pior, representa um comprometimento: se em uma versão futura a classe for modificada para não precisar mais usar as constantes, ainda deverá implementar a interface para garantir a compatibilidade binária. Se uma classe não final implementa uma interface constante, todas as suas subclasses terão seus espaços de nomes poluídos pelas constantes na interface.
Eles são úteis se você tiver constantes comuns que serão usadas nas classes que implementam a interface.
Aqui está um exemplo: http://www.javapractices.com/topic/TopicAction.do?Id=32
Mas observe que a prática recomendada é usar importações estáticas em vez de constantes nas interfaces. Aqui está uma referência: http://www.javapractices.com/topic/TopicAction.do?Id=195
Há respostas muito ressonáveis.
Mas tenho algumas reflexões sobre esta questão. (pode estar errado)
Na minha opinião, os campos em uma interface não devem ser constantes para todo o projeto, são apenas meios para a interface e as interfaces a estendem e as classes que implementam essas interfaces ou têm uma relação próxima com elas. Eles devem ser usados dentro de um certo intervalo, não global.
Dois pontos sobre a interface:
Uma interface descreve um subconjunto do que um objeto que implementa ele pode fazer. (Esta é a intuição)
Uma interface descreve constantes comuns seguidas por objetos que a implementam.
Então, acho que se a Interface Constants não for usada para constantes globais , é aceitável:
implements
ela (e, é claro, use essas constantes comuns na implementação).Exemplo:
interface Drawable {
double GOLDEN_RATIO = 1.618033988;
double PI = 3.141592653;
...
// methods
...
}
public class Circle implements Drawable {
...
public double getCircumference() {
return 2 * PI * r;
}
}
void usage() {
Circle circle = new Circle(radius: 3.0);
double maxRadius = 5.0;
if ( circle.getCircumference() < 2 * Circle.PI * maxRadius ) {
...
}
}
Neste exemplo:
Circle implements Drawable
, você imediatamente sabe que Circle
provavelmente está em conformidade com as constantes definidas em Drawable
, caso contrário, elas têm que escolher um nome pior desde os bons PI
e GOLDEN_RATIO
já foram usadas!Drawable
objetos estão em conformidade com o específico PI
e GOLDEN_RATIO
definido em Drawable
, pode haver objetos que não tenham Drawable
precisão diferente de pi e proporção áurea.A javax.swing.SwingConstants
interface é um exemplo que tem campos estáticos que são usados entre as classes swing. Isso permite que você use facilmente algo como
this.add(LINE_START, swingcomponent);
this.add(this.LINE_START, swingcomponent);
ou this.add(SwingComponents.LINE_START, swingcomponent);
No entanto, essa interface não possui métodos ...
Me deparei com essa pergunta e pensei em adicionar algo que não foi mencionado. Em geral, eu concordo com a resposta de Pascal aqui . No entanto, não acho que as constantes em uma interface sejam "sempre" um antipadrão.
Por exemplo, se as constantes que você está definindo fazem parte de um contrato para essa interface, acho que a interface é um ótimo local para as constantes. Em alguns casos, não é apropriado validar seus parâmetros em particular sem expor o contrato aos usuários da sua implementação. Sem um contrato público, os usuários só podem adivinhar com o que você está validando, além de descompilar a classe e ler seu código.
Portanto, se você implementar uma interface e a interface tiver as constantes usadas para garantir seus contratos (como intervalos inteiros, por exemplo), um usuário da sua classe poderá ter certeza de que está usando a instância da interface corretamente, verificando as constantes na interface si mesmos. Isso seria impossível se as constantes fossem privadas da sua implementação ou se a sua implementação fosse privada do pacote ou algo assim.
Eu uso constantes de interface ao lidar com constantes compartilhadas entre classes.
public interface TestConstants
{
String RootLevelConstant1 = "RootLevelConstant1";
interface SubGroup1
{
String SubGroupConstant1 = "SubGroup1Constant1";
String SubGroupConstant2 = "SubGroup1Constant2";
}
interface SubGroup2
{
String SubGroupConstant1 = "SubGroup2Constant1";
String SubGroupConstant2 = "SubGroup2Constant2";
}
}
O agrupamento é um grande trunfo, especialmente com um grande conjunto de constantes.
Para usar, basta encadeá-los:
System.out.println(TestConstants.SubGroup1.SubGroupConstant1);
System.out.println(TestConstants.SubGroup2.SubGroupConstant1);
System.out.println(TestConstants.RootLevelConstant1);