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 final
como 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.
default
métodos. Eu estou falando sobrestatic
métodos e campos. Como não são herdadas, não quebram a herança múltipla.Respostas:
Colocar constantes nas interfaces é chamado de
Constant Interface Antipattern
constantes, pois muitas vezes são apenas um detalhe de implementação. Outras desvantagens estão resumidas no artigo da Wikipedia sobre a interface Constant .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.
fonte
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:
super()
no call, mas a interface pode ser "implementada"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":
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.
fonte
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.
fonte
interface ColorFilter {Image applyGradient(int colorSpace, int width, byte[] pixels); }
. Eu posso imaginar que haja algumas constantes diferentesRGB
,RGBA
,CMYK
,GREYSCALE
,INDEXED
etc.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 emjava.util.function
ejava.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
enum
que 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.fonte
Que tal compatibilidade com JVMs mais antigas?
Não. É uma mudança incompatível com versões anteriores que adiciona zilch à expressividade do idioma. Dois polegares para baixo.
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.
fonte