Eine einfache Möglichkeit, die Einstellungen einer Java-Anwendung beizubehalten, ist eine Textdatei mit der Erweiterung ".properties", die die Kennung jeder Einstellung enthält, die einem bestimmten Wert zugeordnet ist (dieser Wert kann eine Zahl, eine Zeichenfolge, ein Datum usw. sein). . C # verwendet einen ähnlichen Ansatz, aber die Textdatei muss den Namen "App.config" haben. In beiden Fällen müssen Sie im Quellcode eine bestimmte Klasse zum Lesen von Einstellungen initialisieren: Diese Klasse verfügt über eine Methode, die den Wert (als Zeichenfolge) zurückgibt, der dem angegebenen Einstellungsbezeichner zugeordnet ist.
// Java example
Properties config = new Properties();
config.load(...);
String valueStr = config.getProperty("listening-port");
// ...
// C# example
NameValueCollection setting = ConfigurationManager.AppSettings;
string valueStr = setting["listening-port"];
// ...
In beiden Fällen sollten wir die aus der Konfigurationsdatei geladenen Zeichenfolgen analysieren und die konvertierten Werte den zugehörigen typisierten Objekten zuweisen (während dieser Phase können Analysefehler auftreten). Nach dem Analyseschritt müssen wir überprüfen, ob die Einstellungswerte zu einem bestimmten Gültigkeitsbereich gehören. Beispielsweise sollte die maximale Größe einer Warteschlange ein positiver Wert sein. Einige Werte können in Beziehung stehen (Beispiel: min <max ), und so weiter.
Angenommen, die Anwendung sollte die Einstellungen sofort nach dem Start laden. Mit anderen Worten, der erste Vorgang, den die Anwendung ausführt, ist das Laden der Einstellungen. Ungültige Werte für die Einstellungen müssen automatisch durch Standardwerte ersetzt werden. Wenn dies bei einer Gruppe von verwandten Einstellungen der Fall ist, werden diese Einstellungen alle mit Standardwerten festgelegt.
Am einfachsten können Sie diese Vorgänge ausführen, indem Sie eine Methode erstellen, die zuerst alle Einstellungen analysiert, dann die geladenen Werte überprüft und schließlich die Standardwerte festlegt. Bei dieser Vorgehensweise ist die Wartung jedoch schwierig: Da die Anzahl der Einstellungen während der Entwicklung der Anwendung zunimmt, wird es immer schwieriger, den Code zu aktualisieren.
Um dieses Problem zu lösen, hatte ich mir überlegt, das Muster der Template-Methode wie folgt zu verwenden.
public abstract class Setting
{
protected abstract bool TryParseValues();
protected abstract bool CheckValues();
public abstract void SetDefaultValues();
/// <summary>
/// Template Method
/// </summary>
public bool TrySetValuesOrDefault()
{
if (!TryParseValues() || !CheckValues())
{
// parsing error or domain error
SetDefaultValues();
return false;
}
return true;
}
}
public class RangeSetting : Setting
{
private string minStr, maxStr;
private byte min, max;
public RangeSetting(string minStr, maxStr)
{
this.minStr = minStr;
this.maxStr = maxStr;
}
protected override bool TryParseValues()
{
return (byte.TryParse(minStr, out min)
&& byte.TryParse(maxStr, out max));
}
protected override bool CheckValues()
{
return (0 < min && min < max);
}
public override void SetDefaultValues()
{
min = 5;
max = 10;
}
}
Das Problem ist, dass wir auf diese Weise für jede Einstellung eine neue Klasse erstellen müssen, auch für einen einzelnen Wert. Gibt es andere Lösungen für diese Art von Problem?
Zusammenfassend:
- Einfache Wartung: Zum Beispiel durch Hinzufügen eines oder mehrerer Parameter.
- Erweiterbarkeit: Eine erste Version der Anwendung kann eine einzelne Konfigurationsdatei lesen, spätere Versionen bieten jedoch möglicherweise die Möglichkeit eines Mehrbenutzer-Setups (der Administrator richtet eine Grundkonfiguration ein, Benutzer können nur bestimmte Einstellungen vornehmen usw.).
- Objektorientiertes Design.
quelle
Antworten:
Im Wesentlichen wird die externe Konfigurationsdatei als YAML-Dokument codiert. Diese werden dann beim Start der Anwendung analysiert und einem Konfigurationsobjekt zugeordnet.
Das Endergebnis ist robust und vor allem einfach zu verwalten.
quelle
Betrachten wir dies unter zwei Gesichtspunkten: der API zum Abrufen der Konfigurationswerte und des Speicherformats. Sie sind oft verwandt, aber es ist hilfreich, sie separat zu betrachten.
Konfigurations-API
Das Muster der Template-Methode ist sehr allgemein, aber ich frage mich, ob Sie diese Allgemeinheit wirklich brauchen. Sie benötigen eine Klasse für jeden Typ von Konfigurationswert. Hast du wirklich so viele Typen? Ich würde vermuten, dass Sie mit nur einer Handvoll auskommen können: Zeichenketten, Ints, Floats, Booleans und Enums. In Anbetracht dessen könnten Sie eine
Config
Klasse haben, die eine Handvoll Methoden enthält:(Ich glaube, ich habe die Generika für das Letzte richtig verstanden.)
Grundsätzlich weiß jede Methode, wie das Parsen des Zeichenfolgenwerts aus der Konfigurationsdatei und das Behandeln von Fehlern behandelt werden und gegebenenfalls der Standardwert zurückgegeben wird. Die Bereichsprüfung für die numerischen Werte ist wahrscheinlich ausreichend. Möglicherweise möchten Sie Überladungen haben, bei denen die Bereichswerte weggelassen werden. Dies entspricht der Angabe eines Bereichs von Integer.MIN_VALUE, Integer.MAX_VALUE. Eine Enumeration ist eine typsichere Methode zum Überprüfen eines Strings anhand einer festgelegten Menge von Strings.
Es gibt einige Dinge, die nicht behandelt werden, wie z. B. mehrere Werte, Werte, die miteinander in Beziehung stehen, dynamische Tabellensuchen usw. Sie könnten spezielle Parsing- und Validierungsroutinen für diese schreiben, aber wenn dies zu kompliziert wird, würde ich anfangen zu hinterfragen ob Sie versuchen, zu viel mit einer Konfigurationsdatei zu tun.
Speicherformat
Java-Eigenschaftendateien eignen sich gut zum Speichern einzelner Schlüssel-Wert-Paare und unterstützen die oben beschriebenen Wertetypen ziemlich gut. Sie könnten auch andere Formate wie XML oder JSON in Betracht ziehen, aber diese sind wahrscheinlich zu teuer, es sei denn, Sie haben Daten verschachtelt oder wiederholt. An diesem Punkt scheint es weit über eine Konfigurationsdatei hinauszugehen ....
Telastyn erwähnte serialisierte Objekte. Dies ist eine Möglichkeit, obwohl die Serialisierung ihre Schwierigkeiten hat. Es ist eine Binärdatei, kein Text, daher ist es schwierig, die Werte zu sehen und zu bearbeiten. Sie müssen sich mit der Serialisierungskompatibilität befassen. Wenn in der serialisierten Eingabe Werte fehlen (z. B. Sie haben der Config-Klasse ein Feld hinzugefügt und lesen eine alte serialisierte Form davon), werden die neuen Felder mit null / null initialisiert. Sie müssen eine Logik schreiben, um zu bestimmen, ob ein anderer Standardwert eingegeben werden soll. Aber zeigt eine Null das Fehlen eines Konfigurationswerts an, oder wurde der Wert als Null angegeben? Jetzt müssen Sie diese Logik debuggen. Schließlich (nicht sicher, ob dies ein Problem ist) müssen Sie möglicherweise noch Werte im serialisierten Objektstrom überprüfen. Es ist möglich (wenn auch unpraktisch), dass ein böswilliger Benutzer einen serialisierten Objektstrom unerkennbar ändert.
Ich würde sagen, ich halte mich an die Eigenschaften, wenn es überhaupt möglich ist.
quelle
Config
Klasse und den Ansatz von Ihnen vorgeschlagenen verwenden:getInt()
,getByte()
,getBoolean()
, etc .. Continuing mit dieser Idee, ich alle zum ersten Mal liest die Werte und ich konnte jeden Wert auf ein Flag assoziieren (Dieses Flag ist falsch, wenn während der Deserialisierung ein Problem aufgetreten ist, z. B. Analysefehler.) Danach konnte ich eine Validierungsphase für alle geladenen Werte starten und Standardwerte festlegen.Wie ich es gemacht habe:
Initialisieren Sie alles auf die Standardwerte.
Analysieren Sie die Datei und speichern Sie die Werte, während Sie fortfahren. Die gesetzten Stellen sind dafür verantwortlich, dass die Werte akzeptabel sind. Schlechte Werte werden ignoriert (und behalten daher den Standardwert bei.)
quelle
Wenn alles, was Sie brauchen, eine einfache Konfiguration ist, mache ich gerne eine einfache alte Klasse dafür. Es initialisiert die Standardeinstellungen und kann von der App über die eingebauten Serialisierungsklassen aus der Datei geladen werden. Die App gibt es dann an Dinge weiter, die es brauchen. Kein Hin und Her mit Parsing oder Konvertierungen, kein Herumdrehen mit Konfigurations-Strings, kein Casting-Müll. Und es macht die Konfiguration Art und Weise leichten Einsatz für Szenarien , in-Code , wo sie benötigt werden , gespeichert / geladen vom Server oder als Voreinstellungen und Weise leichten Einsatz in Ihren Unit - Tests.
quelle
Zumindest in .NET können Sie ziemlich einfach Ihre eigenen stark typisierten Konfigurationsobjekte erstellen. In diesem MSDN-Artikel finden Sie ein kurzes Beispiel.
Protip: Hüllen Sie Ihre Konfigurationsklasse in eine Schnittstelle und lassen Sie Ihre Anwendung damit sprechen. Macht es einfach, gefälschte Konfigurationen für Tests oder für den Profit zu erstellen.
quelle
ConfigurationElement
Klasse eine Gruppe von Werten darstellen, und für jeden Wert kann ein Validator angegeben werden. Wenn ich zum Beispiel ein Konfigurationselement darstellen wollte, das aus vier Wahrscheinlichkeitswerten besteht, werden die vier Wahrscheinlichkeitswerte korreliert, da ihre Summe gleich 1 sein muss. Wie validiere ich dieses Konfigurationselement?