J'ai récemment remarqué qu'il existe une option pour avoir des méthodes statiques dans les interfaces. Comme pour les champs d'interface statiques, il existe un comportement intéressant: ceux-ci ne sont pas hérités.
Je ne suis pas sûr que ce soit utile dans les interfaces réelles qui doivent être implémentées. Cependant, cela permet au programmeur de créer des interfaces qui ne sont que des enveloppes pour des éléments statiques, comme par exemple les classes utilitaires.
Un exemple simple est juste une enveloppe pour les constantes globales. Par rapport à une classe, vous pouvez facilement remarquer le passe-partout manquant public static final
lorsque ceux-ci sont supposés (le rendant moins verbeux).
public interface Constants {
String LOG_MESSAGE_FAILURE = "I took an arrow to the knee.";
int DEFAULT_TIMEOUT_MS = 30;
}
Vous pouvez également rendre quelque chose de plus complexe, comme ce pseudo-énumération de clés de configuration.
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;
}
}
Vous pouvez également créer une "classe" utilitaire de cette façon. Cependant, dans les utilitaires, il est souvent utile d'utiliser des méthodes d'assistance privées ou protégées, ce qui n'est pas tout à fait possible dans les classes.
Je considère que c'est une nouvelle fonctionnalité intéressante, et surtout le fait que les membres statiques ne sont pas hérités est un concept intéressant qui a été introduit uniquement pour les interfaces.
Je me demande si vous pouvez considérer cela comme une bonne pratique. Bien que le style de code et les meilleures pratiques ne soient pas axiomatiques et qu'il y ait de la place pour l'opinion, je pense qu'il y a généralement des raisons valables pour appuyer l'opinion.
Je suis plus intéressé par les raisons (non) d'utiliser des modèles comme ceux-ci.
Notez que je n'ai pas l'intention d'implémenter ces interfaces. Ils ne sont qu'une enveloppe pour leur contenu statique. J'ai seulement l'intention d'utiliser les constantes ou les méthodes et éventuellement d'utiliser l'importation statique.
default
méthodes. Je parle destatic
méthodes et de domaines. Ceux-ci ne sont pas hérités, ils ne cassent donc pas l'héritage multiple.Réponses:
Mettre des constantes sur les interfaces s'appelle le
Constant Interface Antipattern
car les constantes ne sont souvent qu'un détail d'implémentation. D'autres inconvénients sont résumés dans l'article Wikipedia sur l' interface Constant .En effet, le document Java indique que les méthodes statiques peuvent faciliter l'organisation des méthodes d'assistance, par exemple lors de l'appel de méthodes d'assistance à partir de méthodes par défaut.
la source
Comme indiqué dans la question, l'interface n'est pas destinée à être implémentée (ou instanciée). Nous pourrions donc le comparer avec une classe qui a un constructeur privé:
super()
appel, mais l'interface peut être "implémentée"new MyInterface() {};
Cette comparaison est en faveur de la classe car elle permet plus de contrôle. Cela dit, la classe n'est pas non plus destinée à contenir des éléments statiques, vous vous attendez à ce qu'elle contienne des instances. Eh bien, il n'y a pas d'option parfaite.
Il y a aussi une chose étrange à propos de l'héritage de "l'interface statique":
Ces raisons peuvent être considérées comme un mauvais modèle et continuer à utiliser des classes statiques pour ces cas. Cependant, pour quelqu'un accro au sucre syntaxique, il peut être tentant même avec les inconvénients.
la source
Comme @MarkusPscheidt, cette idée est essentiellement une extension de l'anti-modèle Constant Interface . Cette approche a d'abord été largement utilisée pour permettre à un seul ensemble de constantes d'être hérité par de nombreuses classes disparates. La raison pour laquelle cela a fini par être considéré comme un contre-motif était due aux problèmes rencontrés lors de l'utilisation de cette approche dans des projets réels. Je ne vois aucune raison de penser que ces problèmes ne concerneraient que les constantes.
Plus important probablement, il n'y a vraiment pas besoin de le faire. Utilisez plutôt des importations statiques et soyez explicite sur ce que vous importez et d'où.
la source
interface ColorFilter {Image applyGradient(int colorSpace, int width, byte[] pixels); }
. Je peux imaginer qu'il y ait des constantes différentesRGB
,RGBA
,CMYK
,GREYSCALE
,INDEXED
etc.Je dirais que si vous souhaitez utiliser correctement la nouvelle fonctionnalité, jetez un œil au code dans le JDK. Les méthodes par défaut sur les interfaces sont très largement utilisées et faciles à trouver, mais les méthodes statiques sur les interfaces semblent être très rares. En voici quelques exemples
java.time.chrono.Chronology
,java.util.Comparator
,java.util.Map
, et un certain nombre d' interfaces dansjava.util.function
etjava.util.stream
.La plupart des exemples que j'ai examinés impliquent des utilisations de ces API qui sont susceptibles d'être très courantes: conversion entre différents types dans l'API temporelle, par exemple, pour des comparaisons susceptibles d'être effectuées fréquemment entre des objets passés à des fonctions ou des objets contenus dans collections. Ma conclusion: s'il y a une partie de votre API qui doit être flexible, mais vous pouvez couvrir 80% des cas d'utilisation avec une poignée de valeurs par défaut, envisagez d'utiliser des méthodes statiques sur vos interfaces. Étant donné la fréquence à laquelle cette fonctionnalité semble être utilisée dans le JDK, je serais très prudent lorsque j'en ferais usage dans mon propre code.
Vos exemples ne ressemblent en rien à ce que je vois dans le JDK. Pour ces cas spécifiques, vous devriez presque certainement créer un
enum
qui implémente l'interface souhaitée. Une interface décrit un ensemble de comportements et n'a vraiment aucun intérêt à maintenir une collection de ses implémentations.la source
Que diriez-vous, euh, de la compatibilité avec les anciennes machines virtuelles Java?
Non. C'est un changement incompatible vers l'arrière qui ajoute du zèle à l'expressivité de la langue. Deux pouces vers le bas.
Je recommande fortement d'utiliser des classes pour contenir les détails d'implémentation. Une interface est simplement destinée à dire "cet objet prend en charge les opérations XYZ" et cela n'a rien à voir avec les méthodes statiques que vous pourriez penser mettre dans la déclaration d'interface. Cette fonction est comme un fauteuil inclinable avec un mini-réfrigérateur intégré. Bien sûr, il a des utilisations de niche, mais il ne tire pas assez de poids pour mériter d'être intégré.
MISE À JOUR: S'il vous plaît plus de downvotes. De toute évidence, certaines personnes pensent que les méthodes statiques dans les interfaces sont les genoux de l'abeille, et je capitule par la présente. Je supprimerais tout de suite cette réponse, mais les commentaires qui y sont joints sont une discussion intéressante.
la source