Verwenden geschachtelter öffentlicher Klassen zum Organisieren von Konstanten

21

Ich arbeite an einer Anwendung mit vielen Konstanten. Bei der letzten Codeüberprüfung stellte sich heraus, dass die Konstanten zu verstreut sind und alle in einer einzigen "Master" -Konstanten-Datei organisiert werden sollten. In der Meinungsverschiedenheit geht es darum, wie man sie organisiert. Die Mehrheit ist der Meinung, dass die Verwendung des Konstantennamens gut genug sein sollte, aber dies führt zu Code, der so aussieht:

public static final String CREDITCARD_ACTION_SUBMITDATA = "6767";
public static final String CREDITCARD_UIFIELDID_CARDHOLDER_NAME = "3959854";
public static final String CREDITCARD_UIFIELDID_EXPIRY_MONTH = "3524";
public static final String CREDITCARD_UIFIELDID_ACCOUNT_ID = "3524";
...
public static final String BANKPAYMENT_UIFIELDID_ACCOUNT_ID = "9987";

Ich finde diese Art der Namenskonvention umständlich. Ich dachte, es könnte einfacher sein, eine öffentliche verschachtelte Klasse zu verwenden und so etwas zu haben:

public class IntegrationSystemConstants
{
    public class CreditCard
    {
        public static final String UI_EXPIRY_MONTH = "3524";
        public static final String UI_ACCOUNT_ID = "3524";
        ...
    }
    public class BankAccount
    {
        public static final String UI_ACCOUNT_ID = "9987";
        ...
    }
}

Diese Idee wurde nicht gut aufgenommen, weil sie "zu kompliziert" war (ich habe nicht viele Details darüber erhalten, warum dies zu kompliziert sein könnte). Ich denke, dies führt zu einer besseren Aufteilung zwischen Gruppen verwandter Konstanten, und die automatische Vervollständigung erleichtert das Auffinden dieser Konstanten. Ich habe dies jedoch noch nie gesehen und frage mich, ob dies eine akzeptierte Praxis ist oder ob es bessere Gründe gibt, warum dies nicht getan werden sollte.

FrustratedWithFormsDesigner
quelle
1
Die Idee gefällt mir eher. In C ++ habe ich etwas Ähnliches gemacht, als ich C # -ähnliche Aufzählungen und Verhaltensweisen wollte, aber mit aussagekräftigen Werten (ich glaube, die Idee entstand, weil ich mich daran gewöhnt hatte, in Scala Fallklassen anstelle von Aufzählungen zu verwenden). Zugegeben, dies war ein persönliches Projekt zum Spaß und keine Teamarbeit.
KChaloux

Antworten:

13

Ich stimme keinem der beiden Vorschläge zu.

Konstanten sollten in ihren jeweiligen Klassen und nicht in einer allkonstanten Klasse in einer der beiden vorgeschlagenen Formen sein .

Es sollte keine Klassen / Interfaces nur mit Konstanten geben.

Eine Klasse CreditCard(keine interne Klasse) sollte existieren. Diese Klasse / Schnittstelle hat Methoden in Bezug auf Kreditkarten sowie die Konstanten UI_EXPIRY_MONTHund UI_ACCOUNT_ID.

Es sollte eine Klasse / Schnittstelle geben BankAccount(keine interne Klasse). Diese Klasse / Schnittstelle hat Methoden, die sich sowohl auf Bankkonten als auch auf Konstanten beziehen UI_ACCOUNT_ID.

Beispielsweise hat in der Java-API jede Klasse / Schnittstelle ihre Konstanten. Sie befinden sich nicht in einer Konstantenklasse / -schnittstelle mit Hunderten von Konstanten, die entweder in innere Klassen gruppiert sind oder nicht.

Diese Konstanten für Ergebnismengen befinden sich beispielsweise in der Schnittstelle ResultSet:

static int  CLOSE_CURSORS_AT_COMMIT 
static int  CONCUR_READ_ONLY 
static int  CONCUR_UPDATABLE 
static int  FETCH_FORWARD 
static int  FETCH_REVERSE 
static int  FETCH_UNKNOWN 
static int  HOLD_CURSORS_OVER_COMMIT 
static int  TYPE_FORWARD_ONLY 
static int  TYPE_SCROLL_INSENSITIVE 
static int  TYPE_SCROLL_SENSITIVE 

Diese Schnittstelle verfügt über Methodensignaturen in Bezug auf Ergebnismengen, und implementierende Klassen implementieren dieses Verhalten. Sie sind nicht nur Konstantenhalter.

Diese Konstanten für UI-Aktionen befinden sich in der Schnittstelle javax.swing.Action:

static String   ACCELERATOR_KEY 
static String   ACTION_COMMAND_KEY 
static String   DEFAULT 
static String   LONG_DESCRIPTION 
static String   MNEMONIC_KEY 
static String   NAME 
static String   SHORT_DESCRIPTION 
static String   SMALL_ICON 

Implementierende Klassen verhalten sich relativ zu UI-Aktionen, sie sind nicht nur konstante Halter.

Ich kenne mindestens eine "Konstanten" -Schnittstelle ( SwingConstants) ohne Methoden, aber sie hat nicht Hunderte von Konstanten, nur einige wenige, und sie hängen alle mit Richtungen und Positionen von UI-Elementen zusammen:

static int  BOTTOM 
static int  CENTER 
static int  EAST 
static int  HORIZONTAL 
static int  LEADING 
static int  LEFT 
static int  NEXT 
static int  NORTH 
static int  NORTH_EAST 
static int  NORTH_WEST 
static int  PREVIOUS 
static int  RIGHT 
static int  SOUTH 
static int  SOUTH_EAST 
static int  SOUTH_WEST 
static int  TOP 
static int  TRAILING 
static int  VERTICAL 
static int  WEST 

Ich denke, nur Konstanten-Klassen sind kein gutes OO-Design.

Tulains Córdova
quelle
1
Ich bin damit einverstanden, dass Konstanten, die nur Klassen sind, in den meisten Fällen ein Zeichen für schlechtes Design sind, aber es gibt legitime Verwendungen. Beispielsweise gehört die Konstante nicht immer zu einer bestimmten Klasse. Ein konkretes Beispiel sind die Tasten für Intent-Extras in der Android-Programmierung.
curioustechizen
1
+1, aber UI-Konstanten sollten wahrscheinlich nicht in Geschäftsmodellen wie BankAccount vorhanden sein. Sie gehören in eine UI-Klasse.
Kevin Cline
10

Es stellte sich heraus, dass die Konstanten zu verstreut sind und alle in einer einzigen "Master" -Konstantendatei organisiert werden sollten.

Dies ist die 100% falsche Lösung für das Problem, dass Konstanten "schwer zu finden" sind. Es ist ein grundlegender Fehler (der leider nur allzu häufig von Programmierern begangen wird), Dinge nach technischen Kriterien wie Konstanten, Aufzählungen oder Schnittstellen zu gruppieren.

Mit Ausnahme von Ebenenarchitekturen sollten die Dinge nach ihrer Domäne gruppiert werden , und dies gilt umso mehr, als es sich um sehr einfache Elemente handelt. Konstanten sollten Teil der Klassen oder Schnittstellen sein, die sie als Teil ihrer API verwenden. Wenn Sie keinen natürlichen Ort zum Leben finden, müssen Sie Ihr API-Design bereinigen.

Darüber hinaus beeinträchtigt eine einzige große Konstantendatei die Entwicklungsgeschwindigkeit in Java, da Konstanten in die Klassen eingefügt werden, die sie zur Kompilierungszeit verwenden. Jede Änderung erzwingt daher eine Neukompilierung aller dieser und aller von ihnen abhängigen Dateien. Wenn Sie eine Datei mit Konstanten haben, die überall verwendet werden, verlieren Sie weitgehend den Vorteil der inkrementellen Kompilierung: Beobachten Sie, wie Eclipse 15 Minuten lang blockiert, während es Ihr gesamtes Projekt für jede Änderung an dieser Datei neu kompiliert. Und da diese Datei alle überall verwendeten Konstanten enthält, werden Sie sie ziemlich oft ändern. Ja, ich spreche aus eigener Erfahrung.

Michael Borgwardt
quelle
Ich war mir der möglichen Auswirkungen auf die Entwicklungsumgebung nicht bewusst, und ich denke, dass der Ansatz der verschachtelten Klassen dabei nicht viel hilft, oder?
FrustratedWithFormsDesigner
1
@FrustratedWithFormsDesigner: Dies hängt davon ab, wie viel Aufwand der inkrementelle Kompilierungsmechanismus für die Modellierung von Abhängigkeiten benötigt.
Michael Borgwardt
9

Du hast recht. Ihr Vorschlag ermöglicht es einem Programmierer, import static Constants.BankAccount.*unzählige Wiederholungen von 'BANKACCOUNT_' zu vermeiden. Verkettung ist ein schlechter Ersatz für das tatsächliche Scoping. Trotzdem hoffe ich nicht sehr, dass Sie die Teamkultur ändern. Sie kennen die richtigen Praktiken und werden sich wahrscheinlich auch dann nicht ändern, wenn Sie ihnen 100 Experten zeigen, die sagen, dass sie falsch sind.

Ich frage mich auch, warum Sie überhaupt eine einzige "Konstanten" -Datei haben. Dies ist eine sehr schlechte Praxis, es sei denn, diese Konstanten hängen alle irgendwie zusammen und sind sehr stabil. Typischerweise wird es zu einer Art Spültischklasse, die sich ständig ändert und von allem abhängig ist.

Kevin Cline
quelle
Wir haben derzeit eine Konstantendatei, die die meisten ID-Konstanten der Benutzeroberfläche enthält, und einige andere Konstantendateien, die subprojektspezifisch sind. Jetzt müssen die teilprojektspezifischen Konstanten jedoch von anderen verwandten Teilprojekten verwendet werden, weshalb die Idee kam, sie alle zu einer "Master" -Konstanten-Datei zusammenzuführen. Welches ist besser als jetzt, weil ich manchmal nicht einmal weiß, welche Konstantendatei für einen Wert neu berechnet werden soll, und jemand anderes ein Duplikat einer Konstante erstellt hat, weil er es nicht in der Konstantendatei eines anderen Unterprojekts finden konnte.
FrustratedWithFormsDesigner
8
Eine Konstanten-Klasse, die sich ständig ändert ... da ist etwas Zen drin, wenn Sie hart genug graben.
KChaloux
2
@FrustratedWithFormsDesigner: UI-Feld-IDs? Sie wissen nicht, wo Sie einen Wert finden sollen? Klingt nach einem riesigen Haufen WTF. Sie haben mein Mitgefühl.
Kevin Cline
6

Beide Ansätze funktionieren, und das ist am Ende des Tages wichtig.

Das heißt, Ihr Ansatz ist weit genug verbreitet, um als Muster oder genauer gesagt als eine hinreichende Verbesserung gegenüber dem Antimuster der konstanten Grenzfläche angesehen zu werden . Ich verstehe nicht, was daran kompliziert ist, aber das ist eine Diskussion, die Sie mit Ihrem Team führen sollten.

yannis
quelle
Für eine ausreichend lange Liste von Konstanten würde ich sogar Konstantenschnittstellen vorziehen, wenn sie alle in derselben Klasse wären. Es ist gefährlich, die falsche Einstellung für die automatische Vervollständigung zu wählen. Das hängt natürlich davon ab, wie lang genug ist :)
Goran Jovic
1
@GoranJovic Nun, jedes Anti-Muster ist in irgendeiner Weise nützlich (oder zumindest praktisch), es würde kein Muster werden, wenn es nicht wäre.
Yannis
1

Eine der Herausforderungen bei der langen Liste von Konstanten besteht darin, die zu verwendende "richtige" Konstante zu finden. Ausnahmslos fügt jemand eine Konstante am Ende der Zeile hinzu, anstatt sie der Gruppe hinzuzufügen, zu der sie gehört.

Was einen weiteren Punkt zur Diskussion mit Ihrem Team aufwirft: Es gibt bereits eine tatsächliche Kategorisierung der Konstanten anhand ihrer Namen. Es sollte für sie also keine große Verschiebung vom aktuellen Stand zu dem sein, was Sie vorschlagen. Durch die Verwendung der automatischen Vervollständigung wird die ständige Suche noch einfacher.

Wenn überhaupt, hilft Ihr Vorschlag dabei, von der Verwendung der "falschen" Konstante abzuraten, auch wenn sie in eine bestimmte Situation passt. Indem die Konstanten in eine repräsentative Klasse eingeschlossen werden, werden die Entwickler angeregt, darüber nachzudenken, ob sie sie verwenden sollten. Wenn ich zum Beispiel CreditCard.SomeConstantfür den allgemeinen Gebrauch ziehe, sollte ich mich wirklich fragen, warum es keine gibtGeneral.SomeConstant stattdessen für diese Situation gibt.

Ich war in Projekten mit Monstermengen an Konstanten und hätte es vorgezogen, die von Ihnen vorgeschlagene Methode zu haben. Es ist sauberer, direkter und vermeidet unbeabsichtigten Gebrauch.


quelle
1

Ich mache das gelegentlich (in C #), besonders wenn ich eine bekannte und feste XML-Struktur oder etwas ähnlich verschachteltes und stringlastiges programmieren muss ... zum Beispiel einen benutzerdefinierten Konfigurationsblock-Parser.

Ich baue eine verschachtelte Klassenstruktur auf, die mit der hierarchischen Struktur des XML übereinstimmt, wobei die Klassennamen den Elementen entsprechen, die eine konstante Zeichenfolge "ElementName" und eine ähnliche Eigenschaft für jedes Attribut enthalten (falls vorhanden).

Es macht es sehr einfach, gegen die entsprechende XML zu programmieren.

Ed Hastings
quelle