A "interface estática" é uma boa prática?

13

Recentemente, notei que há uma opção para ter métodos estáticos nas interfaces. Assim como nos campos estáticos da interface, há um comportamento interessante: eles não são herdados.

Não tenho certeza se é útil nas interfaces reais a serem implementadas. No entanto, ele permite que o programador crie interfaces que são apenas envelopes para coisas estáticas, como, por exemplo, as classes utilitárias.

Um exemplo simples é apenas um envelope para constantes globais. Comparado a uma classe, você pode observar facilmente o padrão que está faltando, public static finalcomo eles são assumidos (tornando-o menos detalhado).

public interface Constants {
    String LOG_MESSAGE_FAILURE = "I took an arrow to the knee.";
    int DEFAULT_TIMEOUT_MS = 30;
}

Você também pode tornar algo mais complexo, como esse pseudo-enum de chaves de configuração.

public interface ConfigKeys {
    static createValues(ConfigKey<?>... values) {
        return Collections.unmodifiableSet(new HashSet(Arrays.asList(values)));
    }

    static ConfigKey<T> key(Class<T> clazz) {
        return new ConfigKey<>(clazz);
    }

    class ConfigKey<T> {
        private final Class<T> type;
        private ConfigKey(Class<T> type) {
            this.type = type;
        }
        private Class<T> getType() {
            return type;
        }
    }
}

import static ConfigKeys.*;
public interface MyAppConfigKeys {
    ConfigKey<Boolean> TEST_MODE = key(Boolean.class);
    ConfigKey<String> COMPANY_NAME = key(String.class);

    Set<ConfigKey<?>> VALUES = createValues(TEST_MODE, COMPANY_VALUE);

    static values() {
        return VALUES;
    }
}

Você também pode criar alguma "classe" de utilidade dessa maneira. No entanto, em utilitários, geralmente é útil usar métodos auxiliares privados ou protegidos, o que não é bem possível nas classes.

Considero um novo recurso interessante e, principalmente, o fato de os membros estáticos não serem herdados é um conceito interessante que foi introduzido apenas nas interfaces.

Gostaria de saber se você pode considerá-lo uma boa prática. Embora o estilo de código e as práticas recomendadas não sejam axiomáticas e haja espaço para opinião, acho que geralmente existem razões válidas para apoiar a opinião.

Estou mais interessado nas razões (não) para usar padrões como esses dois.


Observe que não pretendo implementar essas interfaces. Eles são apenas um envelope para o seu conteúdo estático. Pretendo apenas usar constantes ou métodos e possivelmente usar importação estática.

Vlasec
fonte
1
Minha reação instintiva a isso é que ela só pode levar a coisas ruins. Embora os métodos estáticos públicos sejam essencialmente apenas funções globais no espaço de nomes. Parece que permitir que qualquer código de implementação em uma Interface vá contra seu objetivo, pois a definição de contrato está ausente. Eu digo deixar implementação parcial para classes abstratas. Vou precisar ler por que isso foi adicionado.
Adrian
Eu tenho que ir por enquanto, mas amanhã escreverei algo. O resumo é que, antes de uma Interface, havia um propósito claro que era claramente separado do objetivo de uma AbstractClass. Agora eles se sobrepõem fortemente de uma maneira que viola a definição independente de idioma de uma interface. Além disso, há casos em que você não pode mais herdar de várias interfaces se elas implementarem métodos padrão. Portanto, agora há exceções à herança de várias interfaces onde não havia nenhuma. Como o Java se desviou drasticamente da definição comum de uma interface ...
Adrian
também poderia confundir os novos desenvolvedores que estão tentando obter um controle adequado dos conceitos fundamentais de OOP, como Interfaces, AbstractClases, quando usar composição em vez de herança, ... etc.
Adrian
Aliester, você está falando sobre defaultmétodos. Eu estou falando sobre staticmétodos e campos. Como não são herdadas, não quebram a herança múltipla.
Vlasec

Respostas:

1

Um exemplo simples é apenas um envelope para constantes globais.

Colocar constantes nas interfaces é chamado de Constant Interface Antipatternconstantes, pois muitas vezes são apenas um detalhe de implementação. Outras desvantagens estão resumidas no artigo da Wikipedia sobre a interface Constant .

Você também pode criar alguma "classe" de utilidade dessa maneira.

De fato, o documento Java afirma que métodos estáticos podem facilitar a organização de métodos auxiliares, por exemplo, ao chamar métodos auxiliares a partir de métodos padrão.

Markus Pscheidt
fonte
1
Eu não acho que isso seja realmente uma resposta para a pergunta feita, pois você pode fazer as duas coisas sem essa nova funcionalidade.
Adrian
Ah, então, pela documentação, ele pretende ser um método auxiliar. No entanto, também é público, o que a contradiz. Portanto, talvez se pretenda também ajudar as classes que implementam a interface. Mas eles não são herdados, portanto, você precisará usar a importação estática para parecer que você a herdou. Bem, obrigado por procurar nos documentos.
Vlasec
2
Não há absolutamente nada de errado em colocar constantes nas interfaces, se essas constantes fizerem parte da API descrita pela interface. A única coisa que é um antipadrão é colocar constantes em interfaces sem métodos e fazer com que as classes implementem a interface apenas para se referir às constantes sem um prefixo de classe. É um abuso de interfaces e, desde a introdução de importações estáticas, completamente obsoleto.
Michael Borgwardt
1

Conforme declarado na pergunta, a interface não deve ser implementada (ou instanciada). Assim, poderíamos compará-lo com uma classe que possui um construtor privado:

  • A classe não pode ser estendida sem super()no call, mas a interface pode ser "implementada"
  • A classe não pode ser instanciada sem reflexões, enquanto a interface pode ser facilmente instanciada como uma classe anônima, simples assim: new MyInterface() {};

Essa comparação é a favor da classe, pois permite mais controle. Dito isto, a classe também não pretende ser portadora de coisas estáticas, você esperaria que ela tivesse instâncias. Bem, não há opção perfeita.

Há também uma coisa estranha sobre a herança da "interface estática":

  • Uma classe "implementando" herda campos, mas não herda métodos estáticos
  • Uma interface de extensão não herda nenhum membro estático
  • (Enquanto uma classe que estende uma classe herda todos os membros não privados ... e como não pode ser estendida por uma interface, há menos espaço para confusão)

Esses podem ser motivos para considerá-lo um padrão ruim e continuar usando classes estáticas para esses casos. No entanto, para alguém viciado em açúcar sintático, ainda pode ser tentador, mesmo com as desvantagens.

Vlasec
fonte
... De qualquer forma, as convenções de codificação de uma equipe podem cobrir esses problemas. Para mim, embora não amarre a mão de um programador quase tão firmemente quanto uma classe com construtor privado, ainda corre menos riscos do que os setters, e os setters são freqüentemente usados.
Vlasec
0

Como @MarkusPscheidt, essa ideia é essencialmente uma extensão do antipadrão da Interface Constante . Essa abordagem foi inicialmente usada amplamente para permitir que um único conjunto de constantes seja herdado por muitas classes diferentes. O motivo pelo qual isso acabou sendo considerado antipadrão foi por causa dos problemas encontrados usando essa abordagem em projetos reais. Não vejo razão para pensar que esses problemas se relacionariam apenas com constantes.

Provavelmente o mais importante: não há realmente necessidade de fazer isso. Use importações estáticas e seja explícito sobre o que está importando e de onde.

JimmyJames
fonte
Sim, as importações estáticas parecem uma idéia melhor do que a herança de constantes e funciona com membros estáticos de classes e interfaces. E é visível apenas dentro da classe / interface.
Vlasec
@Vlasec Certo, mas não há necessidade de fazer isso em uma interface. A única diferença entre fazer isso com uma classe e uma interface é que você pode herdar de mais de uma interface. A prática padrão para uma classe de utilidade como essa é tornar o construtor privado para evitar instanciação ou extensão. Não há nenhum benefício em fazer isso em uma interface em uma classe. Simplesmente abre a porta para uso indevido.
JimmyJames
Eu posso ver o valor em constantes nas interfaces. As interfaces tendem a definir métodos e métodos às vezes aceitam constantes como parâmetros. Por exemplo: interface ColorFilter {Image applyGradient(int colorSpace, int width, byte[] pixels); }. Eu posso imaginar que haja algumas constantes diferentes RGB, RGBA, CMYK, GREYSCALE, INDEXEDetc.
Stijn de Witt
@StijndeWitt Isso não seria a pior coisa, mas você pode usar uma enumeração ou classe aninhada na interface para esse fim. O problema real é usá-lo para incluir a estática no escopo de muitas classes através da herança. Essa abordagem é claramente inferior ao uso de importações estáticas.
precisa saber é o seguinte
0

Eu diria que, se você estiver interessado em usar o novo recurso corretamente, consulte o código no JDK. Os métodos padrão nas interfaces são muito usados ​​e fáceis de encontrar, mas os métodos estáticos nas interfaces parecem muito incomuns. Alguns exemplos incluem java.time.chrono.Chronology, java.util.Comparator, java.util.Map, e algumas interfaces de bastante em java.util.functione java.util.stream.

A maioria dos exemplos que eu analisei envolve o uso dessas APIs que provavelmente são muito comuns: conversão entre tipos diferentes na API de tempo, por exemplo, para comparações que provavelmente são feitas com frequência entre objetos passados ​​para funções ou objetos contidos em coleções. Meu argumento: se há uma parte da sua API que precisa ser flexível, mas você pode cobrir, digamos, 80% dos casos de uso com alguns padrões, considere usar métodos estáticos em suas interfaces. Dado o quão pouco frequente esse recurso parece ser usado no JDK, eu seria muito conservador ao usá-lo em meu próprio código.

Seus exemplos não se parecem com o que vejo no JDK. Para esses casos específicos, você quase certamente deve criar um enumque implemente a interface desejada. Uma interface descreve um conjunto de comportamentos e realmente não é necessário manter uma coleção de suas implementações.

ngreen
fonte
-1

Gostaria de saber se existem razões para não usá-lo.

Que tal compatibilidade com JVMs mais antigas?

Você considera isso uma boa ideia em geral?

Não. É uma mudança incompatível com versões anteriores que adiciona zilch à expressividade do idioma. Dois polegares para baixo.

Existem algumas situações de modelo em que você recomenda fortemente aulas?

Eu recomendo o uso de classes para conter detalhes de implementação. Uma interface realmente significa apenas "este objeto suporta operações XYZ" e isso não tem nada a ver com os métodos estáticos que você pode pensar em colocar na declaração da interface. Esse recurso é como uma poltrona reclinável com um frigobar embutido. Claro que ele tem alguns usos de nicho, mas não puxa peso suficiente para merecer ser popular.

UPDATE: Por favor, não mais votos negativos. Claramente, algumas pessoas pensam que métodos estáticos nas interfaces são os joelhos da abelha, e eu estou aqui capitulando. Eu excluiria logo essa resposta, mas os comentários anexados a ela são uma discussão interessante.

DepressedDaniel
fonte
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
maple_shaft
Se eu rebaixasse sua pergunta, faria isso porque nossas duas primeiras respostas não são reais. A nova versão da linguagem traz novas ferramentas para facilitar as coisas, esse é o próprio objetivo dessas novas versões. A terceira resposta está meio perdida nos escombros das duas primeiras.
Vlasec