Je comprends théoriquement pourquoi il n’existe pas deabstract staticen Java, comme expliqué par exemple dans Pourquoi les méthodes statiques ne peuvent-elles pas être abstraites en Java .
Mais comment puis-je résoudre un tel problème alors?
Mon application utilise des fichiers de quelques types, auxquels je souhaite attribuer des propriétés statiques, comme une description de ce type de fichier (comme "fichier de données", l'autre étant "fichier de configuration", etc.). mettrait cela dans une chaîne statique afin que la description soit accessible sans instancer un fichier (utile pour l'interface graphique fi). D'un autre côté, il est évident que tous les types de fichiers doivent avoir des méthodes communes comme getStatus()
vouloir hériter d'une super-classe commune MyFileType
.
getDescription()
serait bien sûr abstrait dans la superclasse.
Essayé d'utiliser une combinaison d'une super-classe et d'une interface, mais problème similaire: une implémentation statique d'une méthode abstraite n'est pas autorisée.
Comment un gourou Java pourrait-il résoudre ce problème? Est-ce vraiment une si mauvaise implémentation que je veux créer?
Merci beaucoup, Philipp
Pour reformuler le problème: vous voulez que vos classes par type de fichier aient des informations statiquement disponibles sur le type (par exemple, nom et description).
Nous pouvons facilement y parvenir: créez une classe distincte pour vos informations de type et disposez-en une instance statique (instanciée de manière appropriée) dans chaque classe de type par fichier.
package myFileAPI;
public class TypeInfo {
public final String name;
public final String description;
public TypeInfo(String name, String description) {
this.name = name;
this.description = description;
}
}
et dis:
package myFileAPI;
public class TextFile {
public static final TypeInfo typeInfo
= new TypeInfo("Text", "Contains text.");
}
Ensuite, vous pouvez faire des choses comme:
System.out.println(TextFile.typeInfo.name);
(Bien entendu, vous pouvez également utiliser des accesseurs dans TypeInfo
pour encapsuler les chaînes sous-jacentes.)
Cependant, comme vous l'avez dit, ce que nous souhaitons réellement, c'est de appliquer l'existence d'une méthode de signature statique particulière dans toutes vos classes par type de fichier au moment de la compilation , mais le paramètre "évident" 'design path conduit à imposer l'utilisation d'une méthode statique abstraite dans une super-classe commune non autorisée.
Nous pouvons appliquons ce au moment de l'exécution cependant, ce qui peut être suffisant pour nous assurer qu'il est codé correctement. Nous introduisons une superclasse de fichiers:
package myFileAPI;
public abstract class File {
public static TypeInfo getTypeInfo() {
throw new IllegalStateException(
"Type info hasn't been set up in the subclass");
}
}
Si TextFile
maintenant extends File
, nous obtiendrons cette exception lors de l'appel de TextFile.getTypeInfo()
à l'exécution, à moins que TextFile ne dispose d'une méthode de même signature.
C'est assez subtil : le code avec TextFile.getTypeInfo()
dans compile encore, même s'il n'y a pas de telle méthode dans TextFile. Même si les méthodes statiques sont liées au moment de la compilation, le compilateur peut toujours consulter la hiérarchie des classes pour déterminer l'appel statique à la compilation, target .
Nous avons donc besoin d'un code comme:
package myFileAPI;
public class TextFile extends File {
private static final TypeInfo typeInfo
= new TypeInfo("Text", "Contains text.");
// Shadow the superclass static method
public static TypeInfo getTypeInfo() {
return typeInfo;
}
}
Notez que nous sommes toujours shadowing la méthode superclass, et donc File.getTypeInfo () peut toujours être appelé "sans signification".
Cela semble être un bon moment pour extraire le théorème fondamental du génie logiciel:
Tout problème peut être résolu en ajoutant une autre couche d'indirection.
Le problème que vous avez ici est qu’un fichier contient plusieurs informations - type de fichier, description du fichier, contenu du fichier, etc. un fichier concret sur le disque et son contenu, et un second qui est une description abstraite d’un type de fichier. Cela vous permettrait de traiter la classe de type de fichier de manière polymorphe. Par exemple:
public interface FileType {
String getExtension();
String getDescription();
/* ... etc. ... */
}
Maintenant, vous pouvez créer des sous-classes pour chacun des types de fichiers que vous utilisez:
public class TextFileType implements FileType {
public String getExtension() {
return ".txt";
}
public String getDescription() {
return "A plain ol' text file.";
}
/* ... */
}
Vous pouvez alors avoir un grand référentiel de ces types d’objets, ce qui vous permettrait d’interroger leurs propriétés sans avoir un fichier ouvert de ce type. Vous pouvez également associer un type à chaque fichier réel que vous utilisez en le faisant simplement stocker une référence FileType
.
La question n'est pas assez claire pour fournir une réponse objective. Puisque je ne peux pas vous donner un poisson, cette réponse est plus sur les lignes de " vous apprendre à pêcher "
Face à des problèmes de conception tels que ceux-ci où vous pensez " duh..Maintenant sûr pourquoi une chose aussi simple est si difficile " plus souvent qu'autrement, vous la concevez de manière flagrante ou vous vous compliquez trop des choses. Si je comprends bien, le problème de conception semble être une "exigence commune", mais le langage ne le permet pas.
... et vous arriverez probablement à une réponse acceptable.
Si ce n'est toujours pas le cas, renvoyez les classes et les interfaces que vous pensez vouloir (avec des erreurs de compilation car le langage n'autorise pas certaines choses) et nous pourrons peut-être vous aider à ajuster votre conception.
les annotations peuvent convenir à vos besoins.
@FileProperties(desc="data file")
public class DataFile extends XFile { ... }
FileProperties props = DataFile.class.getAnnotation(FileProperties.class);
String desc = props.desc();
L'accès aux informations nécessite toujours une réflexion, mais c'est un peu mieux que d'utiliser un champ/une méthode statique.
Le compilateur Java n'impose pas que toutes les sous-classes soient annotées en tant que telles. Vous pouvez ajouter votre logique au compilateur (à l'aide du traitement des annotations), mais c'est trop compliqué. C'est ok pour le vérifier au moment de l'exécution.
Mettre à jour:
Ceci est également possible:
@FileInfoClass ( DataFileInfo.class )
@public class DataFile
Au lieu de placer vos propriétés statiques dans des propriétés statiques, placez une référence à MyFileTypeDescription en tant que propriété statique.
c'est à dire.
class MyFileType {
static MyFileTypeDescription description;
...
<your regular attributes>
}
abstract class MyFileTypeDescription {
String name;
abstract String getDescription();
}
Quelque chose dans cette direction, si j'ai bien compris votre problème.
J'ai fondamentalement eu exactement le même problème.
Vous voudrez peut-être examiner les solutions proposées dans ma question
J'ai aimé l'idée de Bozho, mais selon lui c'était une mauvaise idée. :) Je suppose que les meilleurs programmeurs peuvent expliquer pourquoi. La solution de Ralph et Jon Skeet fonctionne également.
On dirait que vous devez utiliser un singleton. En gros, vous appelez une méthode statique telle que MyFileTypes.getDataFileInstance()
qui crée une instance unique (ou réutilise si déjà créé) d’un objet et lors de sa création, configurez les «constantes» selon vos besoins. Je vais voir si je peux vous trouver un bon exemple, mais votre article ne dit pas très bien comment vous voulez l'utiliser.
Vous pouvez créer une classe FileMetadata contenant toutes les informations nécessaires. Lorsque votre application démarre, vous pouvez créer des instances de FileMetadata et leur conserver des pointeurs statiques afin de pouvoir y accéder à partir de n’importe où dans la JVM.
De cette façon, vous mettez le contenu abstrait dans les instances réelles; tout ce qui ne nécessite pas de sémantique abstraite peut être statique ...
Je ne sais pas comment un gourou Java le résoudrait, mais je créerais probablement un bundle de ressources avec toutes les descriptions dans un fichier de propriétés comme celui-ci:
com.bigcompany.smallapp.files.DataFile=Data file
com.bigcompany.smallapp.files.ConfigFile=Config file
La manipulation du paquet peut être commodément placée dans la superclasse ou ailleurs.
Une autre option consiste à utiliser la réflexion pour accéder aux champs statiques de chaque sous-classe, mais vous devez ensuite vous assurer que toutes les sous-classes ont un champ statique portant le même nom.
Il pourrait également y avoir d'autres options, allant même jusqu'à refactoriser le code afin que les sous-types ne soient pas représentés par une classe distincte, mais en général, il n'y a pas de solution étanche.