2016-01-07 3 views
7

Die Frage, wo in Java Konstanten zu definieren sind, ist in Foren oft aufgetaucht, aber ich habe Mühe, eine Lösung zu finden, mit der ich mich wohl fühle.Wo gibt es Konstanten in Java, die in einigen nicht verwandten Klassen verwendet werden?

Um es einfach zu machen, nehme ich an, ich habe zwei Klassen: WriteMyData und ReadMyData. Keine ist eine Unterklasse der anderen. Beide Klassen teilen sich zwei Konstanten, die für ihren Betrieb unerlässlich sind: String DELIMITER und int LENGTH. In der Zukunft möchte ich vielleicht den Wert dieser Konstanten ändern, damit sie irgendwo passend definiert werden sollten.

Der Konsens scheint oft den enum Typ zu bevorzugen. Allerdings gibt es nichts zu in meinem Fall aufzuzählen, so dass ich am Ende mit nur einem Punkt in meinem enum die ich nennen DEFAULT:

public enum DataSettings { 
    DEFAULT(",", 32); 

    private final String delimiter; 
    private final int length; 

    DataSettings(String delmiter, int length) { 
     this.delimiter = delimiter; 
     this.length = length; 
    } 

    public String getDelimiter() { return delimiter; } 
    public int getLength() { return length; } 
} 

So in meinen beiden Klassen greife ich auf die Konstanten durch DataSettings.DEFAULT.getDelimiter() und DataSettings.DEFAULT.getLength() .

Ist das wirklich ein guter OO-Stil? Ist die Verwendung von enum vielleicht Overkill? Wenn ich nicht enum verwende, was sollte ich stattdessen tun? Das Erstellen einer Schnittstelle für Konstanten scheint verpönt zu sein, und es scheint keine natürliche Oberklasse zu geben, aus der meine Klassen ableiten könnten. Ist es ein Anfängerfehler, nur einen Standard Artikel in einem enum zu haben?

+0

Wenn es nichts aufzuzählen gibt - dh es gibt nur eine Dateneinstellung - machen Sie es einfach zu einer statischen Klasse mit Delimiter und Länge als öffentliche statische Endvariablen – mixmastered

+0

Zeigt diese Variable auf denselben Wert? Willst du konstante Variable an einem Ort deklarieren? – iMBMT

+0

Idealerweise sollte es eine zusätzliche Klasse geben, die alle Variablen als 'public static final' enthält. –

Antwort

2

Wenn nur diese beiden constans und nicht mehr haben, als das, können Sie eine Schnittstelle haben wie

interface DataSetting 
{ 
    String DELIMITER = ","; 
    int LENGTH = 32; 
} 

Und wenn Sie mit nur

public class DataSetting { 

    public static String DELIMITER = ","; 
    public static int LENGTH = 32; 

    static { 
    DELIMITER = System.getProperty("delimiter"); 
    LENGTH = Integer.parseInt(System.getProperty("length")); 
    // or from config 
    } 
} 
+0

@ Eng.Fouad Kopieren Einfügen Fehler :-) – vels4j

+0

Sie können sie entfernen, da sie redundant sind :) –

+0

Viele Menschen scheinen zu vermeiden, Schnittstellen für diesen Zweck verwenden, die mir Angst gemacht, aber anscheinend ist es bekannt als die Constant-Schnittstelle: https : //en.wikipedia.org/wiki/Constant_interface – DustByte

0

Eine Aufzählung durch Eigenschaft initilize 1 Wert ist möglicherweise nicht sehr sinnvoll, obwohl es nützlich sein könnte, wenn Sie Plan auf die Erweiterung der Werte, die es enthalten könnte.

Eine Alternative zu dem, was Sie wie folgt zu tun wäre, sagen:

  1. Haben Sie eine öffentliche Klasse, die projektweite Konstanten aussetzt. Sie können diese Klasse veranlassen, ihre Werte aus einer Konfigurationsdatei zu laden, wenn Ihre Anwendung gestartet wird, damit Sie die Werte dieser Konstanten steuern können.

  2. Haben Sie eine separate Reihe von Methoden mit WithDefaultValues für Ihre Lese-und Schreibmethoden suffixed. Diese Methoden rufen wiederum Ihre anderen Methoden auf und übergeben die Standardparameter.

Als Randbemerkung, könnte es sinnvoll, einfach Überlastung die Methoden, die Sie bereits haben, so dass Sie eine Implementierung haben, die standardmäßig auf diese Konstanten. Wenn dies der Fall ist, sollten Sie dies in der Signatur Ihrer Methode dokumentieren.

3

Erstellen Sie einfach etwas wie Constants.java Klasse, wo Sie alle Konstanten setzen werden.

Zum Beispiel:

public class Constants { 
    public static final String DELIMITER = "-"; 
    public static final int LENGTH = 1; 
} 

Und sie verwenden, wo Sie wollen von:

Constants.DELIMITER 
Constants.LENGTH 
+0

Erklären Sie zu OP, warum Klasse nicht Schnittstelle? – iMBMT

+2

Ich entnehme dem Lesen in Foren, dass es eine schlechte Übung ist, eine Klasse nur für Konstanten zu haben, da sie im Laufe der Zeit mit nicht verwandten Konstanten übersät ist, die weit entfernt von dem erscheinen, wo sie anwendbar sind. – DustByte

+1

@bmt Einfach weil Schnittstellen einen bestimmten Zweck haben und sicherlich Konstanten speichern, gehört nicht dazu.Schnittstellen sind für Specyfing API, nicht zum Speichern von Daten. In jedem Anwendungsfall, der sich von den Schnittstellen unterscheidet, sollte die Klasse verwendet werden. Zunächst würde ich fragen, warum hier eine Schnittstelle zu verwenden ist. Und wenn der Grund, sie zu verwenden, darin besteht, dass ihre Variablen implizit "öffentliches statisches Finale" sind und wir es nicht von Hand machen müssen, ist das kein guter Grund. Um den OOP-Regeln zu entsprechen, sollte Klasse verwendet werden. – ctomek

0

IMO ist Enum Overkill in diesem Fall. Enums sind für Aufzählungen gemacht.

Für globale Konstanten, können Sie nur ein öffentliches statisches Attribut final Klasse erstellen in einer Java-Klasse oder Java-Schnittstelle, obwohl das späteste nicht der üblicher Ansatz ist (siehe Interfaces with static fields in java for sharing 'constants')

0

ich eine andere Lösung vorschlagen würde, die doesn Verwenden Sie keine Konstanten in WriteMyData und ReadMyData.

Trennzeichen und Länge als Konstruktorparameter übergeben. Auf diese Weise können Sie diese Klassen mit Parametern testen, die das Testen vereinfachen.

Wenn es wichtig ist, dass eine Instanz von jedem die gleichen Werte für Trennzeichen und Länge verwendet, sollten beide am gleichen Ort instanziiert und für die Clients verfügbar gemacht werden. Der Ort, an dem die Instanzen erstellt werden, ist ein geeigneter Ort für Konstanten für die Werte von Begrenzer und Länge.

0

Sie können eine Schnittstelle erstellen.
Standardmäßig sind Konstanten in der Schnittstelle statisch und final.
Und Sie können diese Variable von Referencing-Schnittstelle verwenden.

public interface AnyNameInterface { 
    String AnyVar ="DEMO"; 
    Double AnyVar_2 = 123.00; 
} 

Anwendung:

AnyNameInterface.AnyVar 
AnyNameInterface.AnyVar_2 
1

eine enum Verwendung, wenn es nichts zu aufzuzählen ist in der Tat eine schlechte Praxis.

Die andere erwähnte Alternative, die interface verwendet, ist auch eine schlechte Wahl. Effective Java Punkt 19 beschreibt es am besten:

Item19: Verwenden Sie Schnittstellen nur Typen definieren

Wenn eine Klasse eine Schnittstelle implementiert, die Schnittstelle als Typ dient, die verwendet werden können, beziehen zu Instanzen der Klasse. Dass eine Klasse eine Schnittstelle implementiert, sollte daher etwas darüber aussagen, was ein Client mit Instanzen der Klasse machen kann. Es ist unangemessen, eine Schnittstelle für andere Zwecke zu definieren.

Eine Art von Schnittstelle, die diesen Test nicht besteht, ist die konstante Schnittstelle. Eine solche Schnittstelle enthält keine Methoden. es besteht ausschließlich aus statischen Endfeldern, von denen jedes eine Konstante exportiert. Klassen, die diese Konstanten verwenden, implementieren die Schnittstelle, um die Notwendigkeit zu vermeiden, konstante Namen mit einem Klassennamen zu qualifizieren.

Die korrekte Umsetzung ist ein nichtinstanziierbare Utility-Klasse zu definieren:

public class Constants { 
    private Constants(){} // Private constructor prevents instantiation AND subclassing 

    public static final String DELIMITER = "-"; 
    public static final int LENGTH = 1; 
} 

Zur Vereinfachung Sie statisch die Konstanten in Ihrem Code importieren:

import static com.example.Constants.*; 

public class Test { 
    public static void main(String[] args){ 
     System.out.println(DELIMITER); // prints "-" 
    } 
} 
0

Ich möchte hinzufügen Selbst wenn es etwas aufzuzählen gibt, können Enums nicht immer als Container für Konstanten verwendet werden, obwohl sie nett sind. B. javax.ws.rs.Path definiert ein einzelnes Annotationstyp-Element vom Typ String Dies wird jedoch nicht kompilieren:

@Path(MyEnum.BASE_PATH) noch wird @Path(MyEnum.BASE_PATH.name())

Auch in den Fällen, wo es nicht möglich, die Konstanten für die Klasse selbst, oder auf einem gemeinsamen übergeordneten Klasse zu definieren, die Diskussion scheint oft zwischen der Definition der Konstanten in einer Klasse vs in einer Schnittstelle zu sein. Eine dritte Möglichkeit könnte darin bestehen, sie in einer Anmerkung zu definieren.

public @interface MyAnnotation { 
    String QUESTIONS = "/questions"; 
    String ANSWERS = "/answers"; } 

Die Anmerkung Ansatz vermeidet die "konstante Schnittstelle" pitfall. Diese Fallstricke ist, in meinem Verständnis, nicht, dass die Schnittstelle als eine Konstante Container an sich ist eine schlechte Idee, - das Problem ist, wenn Anrufer implementieren die Schnittstelle, anstatt den Zugriff auf die Konstanten durch zB. ein statischer Import

Verwandte Themen