Ich hatte gerade eine Diskussion über eine Designauswahl nach einer Codeüberprüfung. Ich frage mich, was deine Meinung ist.
Es gibt diese Preferences
Klasse, die ein Bucket für Schlüssel-Wert-Paare ist. Nullwerte sind legal (das ist wichtig). Wir gehen davon aus, dass bestimmte Werte möglicherweise noch nicht gespeichert wurden, und möchten diese Fälle automatisch behandeln, indem wir sie auf Anforderung mit einem vordefinierten Standardwert initialisieren.
Die besprochene Lösung verwendete folgendes Muster (HINWEIS: Dies ist offensichtlich nicht der eigentliche Code - es wird zur Veranschaulichung vereinfacht):
public class Preferences {
// null values are legal
private Map<String, String> valuesFromDatabase;
private static Map<String, String> defaultValues;
class KeyNotFoundException extends Exception {
}
public String getByKey(String key) {
try {
return getValueByKey(key);
} catch (KeyNotFoundException e) {
String defaultValue = defaultValues.get(key);
valuesFromDatabase.put(key, defaultvalue);
return defaultValue;
}
}
private String getValueByKey(String key) throws KeyNotFoundException {
if (valuesFromDatabase.containsKey(key)) {
return valuesFromDatabase.get(key);
} else {
throw new KeyNotFoundException();
}
}
}
Es wurde als Anti-Pattern kritisiert - Missbrauch von Ausnahmen, um den Fluss zu kontrollieren . KeyNotFoundException
- nur für diesen einen Anwendungsfall zum Leben erweckt - wird niemals aus dem Rahmen dieser Klasse herausgesehen.
Es sind im Wesentlichen zwei Methoden, die damit spielen, nur um etwas miteinander zu kommunizieren.
Der Schlüssel, der nicht in der Datenbank vorhanden ist, ist nicht alarmierend oder außergewöhnlich. Dies wird erwartet, wenn eine neue Voreinstellung hinzugefügt wird, daher der Mechanismus, der ihn bei Bedarf ordnungsgemäß mit einem Standardwert initialisiert.
Das Gegenargument war, dass getValueByKey
die private Methode, wie sie derzeit definiert ist, keine natürliche Möglichkeit bietet, die öffentliche Methode sowohl über den Wert als auch darüber zu informieren , ob der Schlüssel vorhanden ist. (Wenn dies nicht der Fall ist, muss es hinzugefügt werden, damit der Wert aktualisiert werden kann.)
Die Rückgabe null
wäre zweideutig, da null
es sich um einen vollkommen legalen Wert handelt. Es lässt sich also nicht sagen, ob der Schlüssel nicht vorhanden war oder ob ein Schlüssel vorhanden war null
.
getValueByKey
Tuple<Boolean, String>
Müsste eine Art von a zurückgeben , das Bool auf true setzen, wenn der Schlüssel bereits vorhanden ist, damit wir zwischen (true, null)
und unterscheiden können (false, null)
. (Ein out
Parameter könnte in C # verwendet werden, aber das ist Java).
Ist das eine schönere Alternative? Ja, Sie müssten eine Klasse für den einmaligen Gebrauch definieren Tuple<Boolean, String>
, aber dann werden wir sie los KeyNotFoundException
, damit diese Art von Ausgleich entsteht. Wir vermeiden auch den Aufwand für die Behandlung von Ausnahmen, obwohl dies praktisch nicht von Bedeutung ist. Es gibt keine nennenswerten Leistungsaspekte, es handelt sich um eine Client-App und es ist nicht so, als würden Benutzereinstellungen millionenfach pro Sekunde abgerufen.
Eine Variation dieses Ansatzes könnte Guavas verwenden Optional<String>
(Guava wird bereits im gesamten Projekt verwendet), anstatt irgendeiner Gewohnheit Tuple<Boolean, String>
, und dann können wir zwischen Optional.<String>absent()
und "richtig" unterscheiden null
. Es fühlt sich jedoch aus Gründen, die leicht zu erkennen sind, immer noch hackisch an - die Einführung von zwei Ebenen der "Nullheit" scheint das Konzept zu missbrauchen, das hinter der Schaffung von Optional
s an erster Stelle stand.
Eine andere Möglichkeit wäre, explizit zu prüfen, ob der Schlüssel existiert (fügen Sie eine boolean containsKey(String key)
Methode hinzu und rufen Sie sie getValueByKey
nur auf, wenn wir bereits bestätigt haben, dass sie existiert).
Schließlich könnte man auch die private Methode einbinden, aber die eigentliche getByKey
ist etwas komplexer als mein Codebeispiel, so dass das Einbetten ziemlich unangenehm aussehen würde.
Ich mag hier Haare spalten, aber ich bin neugierig, worauf Sie wetten würden, um in diesem Fall der besten Praxis am nächsten zu sein. Ich habe in den Styleguides von Oracle oder Google keine Antwort gefunden.
Ist die Verwendung von Ausnahmen wie im Codebeispiel ein Anti-Pattern, oder ist es akzeptabel, da Alternativen auch nicht sehr sauber sind? Wenn ja, unter welchen Umständen wäre das in Ordnung? Und umgekehrt?
getValueByKey
auch öffentlich ist.