32 Stimmen

Java: statische abstrakte (wieder) - beste Praxis, wie man umgeht

Ich verstehe theoretisch, warum es keine abstrakt statisch in Java, wie zum Beispiel erklärt in Warum können statische Methoden in Java nicht abstrakt sein? .

Aber wie löse ich dann ein solches Problem?

Meine Anwendung verwendet einige Dateitypen, denen ich statische Eigenschaften wie eine Beschreibung des Dateityps zuweisen möchte (z. B. "Datendatei", die andere ist "Konfigurationsdatei" usw.). Natürlich würde ich das in einen statischen String packen, so dass die Beschreibung zugänglich ist, ohne eine Datei zu instanzieren (nützlich z.B. für die GUI). Andererseits sollten natürlich alle Dateitypen einige gemeinsame Methoden haben wie getStatus() , die ich natürlich von einer gemeinsamen Oberklasse erben möchte MyFileType .

getDescription() wäre natürlich in der Oberklasse abstrakt.

Ich habe versucht, eine Kombination aus einer Oberklasse und einer Schnittstelle zu verwenden, aber das Problem ist ähnlich: Eine statische Implementierung einer abstrakten Methode ist nicht zulässig.

Wie würde ein Java-Guru dieses Problem lösen? Ist es wirklich eine so schlechte Implementierung, die ich erstellen möchte?

Vielen Dank! Philipp

37voto

Stuart Rossiter Punkte 2212

Um das Problem noch einmal zu verdeutlichen: Sie möchten, dass Ihre Klassen pro Dateityp statisch verfügbare Informationen über den Typ haben (z. B. Name und Beschreibung).

Wir können leicht einen Teil des Weges dorthin gehen: Erstellen Sie eine separate Klasse für Ihre Typinformationen und haben Sie eine statische Instanz davon (entsprechend instanziiert) in jeder Klasse pro Dateityp.

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;
    }
}

und, sagen wir:

package myFileAPI;

public class TextFile {
    public static final TypeInfo typeInfo
                   = new TypeInfo("Text", "Contains text.");
}

Dann können Sie Dinge tun wie:

System.out.println(TextFile.typeInfo.name);

(Natürlich können Sie auch Getter in TypeInfo um die zugrunde liegenden Zeichenketten zu kapseln).

Aber wie Sie schon sagten, wollen wir eigentlich nur durchsetzen. das Vorhandensein einer bestimmten statischen Methode mit Signatur in allen Ihren dateitypischen Klassen zur Kompilierzeit aber der "offensichtliche" Entwurfspfad führt dazu, dass eine abstrakte statische Methode in einer gemeinsamen Oberklasse erforderlich ist, was nicht zulässig ist.

Wir puede dies durchsetzen während der Laufzeit was jedoch ausreichen kann, um sicherzustellen, dass sie korrekt kodiert ist. Wir führen eine Oberklasse File ein:

package myFileAPI;

public abstract class File {

    public static TypeInfo getTypeInfo() {
        throw new IllegalStateException(
                    "Type info hasn't been set up in the subclass");
    }

}

Wenn TextFile jetzt extends File erhalten wir diese Ausnahme beim Aufruf von TextFile.getTypeInfo() zur Laufzeit, es sei denn, TextFile hat eine Methode mit gleicher Unterschrift.

Dies ist ziemlich subtil Code mit TextFile.getTypeInfo() in kompiliert immer noch, auch wenn es keine solche Methode in TextFile gibt. Auch wenn statische Methoden zur Kompilierzeit gebunden werden, kann der Compiler immer noch die Klassenhierarchie durchsuchen, um das Ziel für den statischen Aufruf zur Kompilierungszeit zu bestimmen .

Wir brauchen also einen Code wie:

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;
    }

}

Beachten Sie, dass wir immer noch Beschattung die Superklassen-Methode, und damit File.getTypeInfo() kann immer noch "sinnlos" genannt werden.

7voto

templatetypedef Punkte 343693

Das klingt nach einem guten Zeitpunkt, um das Fundamental Theorem of Software Engineering hervorzuholen:

Jedes Problem kann durch Hinzufügen einer weiteren Ebene der Umgehung gelöst werden.

Das Problem, das Sie hier haben, ist, dass eine Datei mehrere Informationen enthält - den Typ der Datei, eine Beschreibung der Datei, den Inhalt der Datei usw. Ich würde vorschlagen, dies in zwei Klassen aufzuteilen - eine Klasse, die eine konkrete Datei auf der Festplatte und ihren Inhalt darstellt, und eine zweite, die eine abstrakte Beschreibung eines Dateityps ist. Dies würde es Ihnen ermöglichen, die Dateitypklasse polymorph zu behandeln. Zum Beispiel:

public interface FileType {
     String getExtension();
     String getDescription();

     /* ... etc. ... */
}

Nun können Sie für jeden der von Ihnen verwendeten Dateitypen Unterklassen erstellen:

public class TextFileType implements FileType {
     public String getExtension() {
         return ".txt";
     }
     public String getDescription() {
         return "A plain ol' text file.";
     }
     /* ... */
}

Sie können dann ein großes Repository dieser Art von Objekten haben, das es Ihnen ermöglicht, ihre Eigenschaften abzufragen, ohne eine offene Datei dieses Typs zu haben. Sie könnten auch jeder Datei, die Sie verwenden, einen Typ zuordnen, indem Sie sie einfach mit einem FileType Hinweis.

3voto

irreputable Punkte 43667

Anmerkungen könnten für Ihren Zweck gut geeignet sein.

@FileProperties(desc="data file")
public class DataFile extends XFile { ... }

FileProperties props = DataFile.class.getAnnotation(FileProperties.class);
String desc = props.desc(); 

Der Zugriff auf die Informationen erfordert immer noch Reflexion, aber es ist ein wenig besser als mit statischen Feld/Methode.

Der Java-Compiler erzwingt nicht, dass alle Unterklassen als solche annotiert werden. Sie können dem Compiler Ihre Logik hinzufügen (unter Verwendung der Annotationsverarbeitung), aber das ist zu kompliziert. Es ist in Ordnung, dies zur Laufzeit zu überprüfen.

Aktualisierung:

Auch das ist möglich:

@FileInfoClass ( DataFileInfo.class )
@public class DataFile

2voto

Amol Katdare Punkte 6644

Die Frage ist nicht klar genug, um eine objektive Antwort zu geben. Da ich Ihnen keinen Fisch geben kann, lautet die Antwort eher: " Bringt euch das Fischen bei " :)

Wenn Sie mit solchen Designfragen konfrontiert werden, denken Sie " Ich weiß nicht, warum so etwas Einfaches so schwierig ist. "In den meisten Fällen haben Sie es entweder falsch konzipiert, oder Sie sind Überkomplizierung Dinge. Wenn ich das richtig sehe, scheint Ihr Designproblem eine "allgemeine Anforderung" zu sein, aber die Sprache lässt keine eleganten Lösungen zu.

  • Verfolgen Sie Ihre Entwurfsschritte/Entscheidungen zurück
  • Hinterfragen Sie alle "offensichtlichen" und "selbstverständlichen" Argumente, auf die Sie sich bei Ihrem Entwurf stützen (Sie verwenden oben ziemlich viele davon)
  • prüfen, ob die Dinge vereinfacht werden können ( keines der OO-Konzepte bis zum logischen Extrem ausreizen . Kompromisse auf der Grundlage des ROI eingehen)

...und Sie werden höchstwahrscheinlich eine akzeptable Antwort erhalten.

Wenn Sie immer noch nicht wissen, posten Sie die Klassen und Schnittstellen, die Sie glauben zu wollen (mit Kompilierfehlern, da die Sprache bestimmte Dinge nicht zulässt), und vielleicht können wir Ihnen helfen, Ihr Design zu optimieren.

0voto

Tommy Punkte 521

Ich hatte im Grunde genau das gleiche Problem.

Vielleicht möchten Sie sich die Lösungen, die mir in meiner Frage vorgeschlagen wurden

Ich mochte Bozhos Idee, aber seiner Meinung nach war es eine schlechte Idee :) Ich nehme an, bessere Programmierer können erklären, warum das so ist. Die Lösung von Ralph und Jon Skeet funktioniert auch.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X