Qual é o uso de constantes de interface?

123

Estou aprendendo Java e acabei de descobrir que a interface pode ter campos públicos estáticos e finais. Eu não vi nenhum exemplo disso até agora. Quais são alguns dos casos de uso dessas constantes de interface e posso ver alguns na Java Standard Library?

unj2
fonte

Respostas:

189

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);
    }
}
Pascal Thivent
fonte
12
Ok, mas e se você tiver uma interface que não seja apenas para definição constante. Então, eu tenho alguma interface que é implementada por muitas classes que contém declarações de métodos, mas eu também quero adicionar também alguns valores comuns, como tamanho, por exemplo. É realmente um padrão ruim neste caso. Em geral, concordo que a criação de interfaces apenas para constantes é um antipadrão.
Łukasz Rzeszotarski
11
Não é uma coisa ruim apenas porque alguém diz isso em um livro. Contanto que você não implemente essa interface para obter acesso a essas constantes, tudo bem.
ACV
11
Não Não Não. Essa citação no Java eficaz é sobre outra coisa! Criar interfaces apenas de constantes é uma alternativa melhor às classes que mantêm essas constantes. Java eficaz diz: "O fato de uma classe usar algumas constantes internamente é um detalhe de implementação". Mas aqui não é o caso. Estamos falando de constantes 'globais'. E quem iria querer implementar uma interface sem declarações de método?
ACV
6
Eu concordo com o ACV. Se a interface constante não fizer parte do módulo da API exportada ou quando não estiver implementada em nenhum lugar, não vejo o problema. O uso de classes finais const é feio: você precisa de um construtor privado que confunda o código, pois ele não tem utilidade.
Lawrence
2
Esta resposta não apresenta o ponto principal do livro "Java efetivo" corretamente, porque "rebaixa" o ponto principal colocando-o entre colchetes: "(e implementando essa interface)". Em vez disso, enfatiza o ponto de constantes nas interfaces (que são boas, a menos que você implemente essa interface). Geralmente, não é uma resposta ruim, porque se você ler atentamente o fragmento citado, poderá ver o que foi originalmente significado pelo autor de "Java Efetivo". Mas acho isso enganoso. Na minha opinião, a parte "e a implementação dessa interface" deve estar em negrito para enfatizá-la.
Krm 10/07/19
17

" 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?

A questão fundamental

é 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.

  1. A falta de percepção para a necessidade de modelo de dados "normalização".

  2. As declarações da EF Codd sobre normalização de dados são falhas, defeituosas e ambíguas.

  3. 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.

Usar constantes de interface é uma boa prática.

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.

Um raciocínio tolo - as interfaces não eram destinadas pelos linguados da linguagem Java a serem usadas dessa maneira?

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.

O uso de constantes enum é realmente uma prática horrível.

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.

As constantes são contrato da API

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.

Uma presunção estranha - e se a interface for inadvertidamente implementada.

Sim. Qualquer um poderia inadvertidamente implementar qualquer interface inadvertidamente. Nada atrapalhará esses programadores inadvertidos.

Projete e normalize seu modelo de dados contra vazamentos

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.

Não usar um IDE é uma prática ruim

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.

Algumas estruturas foram projetadas para ajudar os programadores a continuar praticando maus hábitos com eficiência.

OSGI é esse quadro. E também o decreto contra as constantes da interface.

Portanto, a resposta conclusiva ...

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.

Blessed Geek
fonte
29
Todos os seus argumentos poderiam ser feitos sem a piada, o sarcasmo, a emocionalidade. O Stackoverflow não é uma plataforma de blog.
tkruse
1
"Eu não ligo para o que as intenções originais dos pais fundadores tinham com a Constituição dos EUA. Eu não ligo para as intenções não escritas não escritas. Eu só ligo para o que é literariamente codificado na Constituição escrita e como posso explorá-las para o funcionamento eficaz da sociedade ". - isso não é uma boa alegoria?
Blessed Geek
"É necessário escrever código extra para mapear parâmetros para valor. O fato de os fundadores do Java não fornecerem mapeamento de valores de parâmetros sem você escrever que o código de mapeamento demonstra que as constantes Enum são o uso não intencional da linguagem Java". De que outra forma você obteria o mapeamento de valor de parâmetro sem escrever código extra?
precisa
Use constantes de interface. EXATAMENTE.
Blessed Geek
9

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.

Por que usar Interface Constant?

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.

Má prática?

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)

Isso não vai acontecer na biblioteca padrão

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.

Debate interminável

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 .

Nakamura
fonte
"Colocar membros estáticos em uma interface (e implementar essa interface) é uma prática ruim". Não, não é
Chovendo
O modificador publictambém pode ser omitido, pois é uma interface, simplificando o double PI = 3.14159;uso de Constants.PInão precisa da classe que usa isso para implementar a Constantsinterface! Eu acho que a abordagem da interface é muito mais limpa em termos de uso, IMHO
krozaine
6

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.

empilhador
fonte
Você adicionou literalmente nada de valor que ainda não havia sido dito.
Donal Fellows
2

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.

Zhili
fonte
Eles realmente devem ser usados ​​nessas classes de implementação.
Estou chovendo
2

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.

    • Essas constantes comuns devem ser conhecidas pelo cliente para saber mais sobre esses objetos.
    • Portanto, a Interface Constants é realmente contra-intuitiva para definir constantes globais , uma vez que a interface é usada para descrever alguns objetos , nem todos os objetos / nenhum objeto (considere o significado de global ).

Então, acho que se a Interface Constants não for usada para constantes globais , é aceitável:

  • Se essas constantes comuns tiverem bons nomes, eles recomendarão que o implementador as use (veja meu primeiro ponto no exemplo abaixo)
  • Se uma classe deseja sincronizar com essas classes seguindo a especificação, apenas implementsela (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:

  • De Circle implements Drawable, você imediatamente sabe que Circleprovavelmente está em conformidade com as constantes definidas em Drawable, caso contrário, elas têm que escolher um nome pior desde os bons PIe GOLDEN_RATIOjá foram usadas!
  • Somente esses Drawableobjetos estão em conformidade com o específico PIe GOLDEN_RATIOdefinido em Drawable, pode haver objetos que não tenham Drawableprecisão diferente de pi e proporção áurea.
Chovendo
fonte
Eu entendi mal a sua resposta ou você entendeu mal o propósito da Interface? Uma interface NÃO deve ser um subconjunto. Uma interface é um contrato, que qualquer que assine o contrato deve fornecer a interação especificada por esse contrato. O único uso válido da interface é usá-lo para declarar / cumprir um contrato.
Blessed Geek
@BlessedGeek Você cumpre um contrato, então a capacidade descrita no contrato é um subconjunto do que você pode fazer.
Chovendo
1

A javax.swing.SwingConstantsinterface é 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 ...

Progman
fonte
1

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.

akagixxer
fonte
1
O problema com interfaces e constantes da maneira que você descreve, você pode adicionar uma constante a uma interface, mas não há nenhuma ligação que imponha o consumidor da sua API a realmente usar essa constante.
Daniel
@ Daniel: Eu votei no seu comentário, mas agora tenho uma boa explicação para sua pergunta: "não há nenhuma ligação que force o consumidor da sua API a realmente usar essa constante", mas agora o cliente não pode mais usar o CONSTANT_NAME porque eles foram usado, o que é um bom sinal para mim!
Raining
Portanto, o nome da constante não está disponível na sua turma, mas isso pressupõe que vou nomear a constante exatamente a mesma coisa. Usar uma interface para representar constantes ainda é uma falácia, uma interface é um contrato para uma API. De maneira alguma deve ser usado para representar valores constantes.
Daniel
-1

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);
jared
fonte
Eu concordaria. Faz basicamente o mesmo que a classe abstrata pública com campos finais estáticos públicos, mas em muito menos palavras. Tudo o que você precisa é garantir que todos os desenvolvedores de sua equipe estejam seguindo boas práticas e não implementem essas interfaces.
Yahor 31/03
1
Isso é horrível, porque você pode fazer exatamente o mesmo com Classes, acessar da mesma maneira e tornar as classes finais e seus construtores privados (se você realmente quiser apenas um conjunto de constantes). Além disso, você evita que as pessoas estendam sua classe. Você não pode evitar pessoas implementando sua interface, pode?
precisa
1
Por que fazer em uma classe o que você pode fazer em uma interface? Como impedir que as pessoas inadvertidamente implementem QUALQUER interface é a questão. Por que você escolhe as constantes da interface?
Blessed Geek
-2

os campos devem ser declarados em uma interface para que sejam mais fáceis de compartilhar e possam ser referenciados sem a introdução de acoplamento extra.

Origem: Java Developer Tools Coding Style

Master Mind
fonte
talvez antes de java6. mas isso é irrelevante hoje em dia.
tkruse
E o link está quebrado. Codepro não existe mais.
Stephen C