Je viens d'avoir une discussion sur un choix de conception après une révision du code. Je me demande quelles sont vos opinions.
Il y a cette Preferences
classe, qui est un compartiment pour les paires clé-valeur. Les valeurs nulles sont légales (c'est important). Nous nous attendons à ce que certaines valeurs ne soient pas encore enregistrées, et nous souhaitons gérer ces cas automatiquement en les initialisant avec une valeur par défaut prédéfinie à la demande.
La solution discutée utilisait le modèle suivant (NOTE: ce n'est pas le code réel, bien entendu - c'est simplifié à des fins d'illustration):
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();
}
}
}
Il a été critiqué comme un anti-modèle - abusant des exceptions pour contrôler le flux . KeyNotFoundException
- mis en oeuvre pour ce seul cas d'utilisation - ne sera jamais considéré comme étant hors de la portée de cette classe.
Il s’agit essentiellement de deux méthodes jouant avec chercher simplement pour communiquer quelque chose l’une à l’autre.
Le fait que la clé ne soit pas présente dans la base de données n'est pas alarmant ni exceptionnel. Nous nous attendons à ce que cela se produise chaque fois qu'un nouveau paramètre de préférence est ajouté. D'où le mécanisme qui l'initialise de manière élégante avec une valeur par défaut si nécessaire.
Le contre-argument était que getValueByKey
- la méthode privée - telle que définie actuellement n’a aucun moyen naturel d’informer la méthode publique à la fois de la valeur et de la présence de la clé. (Si ce n'est pas le cas, il faut l'ajouter pour que la valeur puisse être mise à jour).
Retourner null
serait ambigu, car null
c'est une valeur parfaitement légale, donc on ne peut pas dire si cela signifiait que la clé n'était pas là, ou s'il y avait un null
.
getValueByKey
devrait renvoyer une sorte de Tuple<Boolean, String>
, bool mis à true si la clé est déjà là, afin que nous puissions distinguer entre (true, null)
et (false, null)
. (Un out
paramètre peut être utilisé en C #, mais c'est Java).
Est-ce une alternative plus agréable? Oui, il faudrait définir une classe à usage unique comme effet Tuple<Boolean, String>
, mais ensuite, nous nous en débarrassons KeyNotFoundException
, ce genre d'équilibre. Nous évitons également la surcharge liée à la gestion d'une exception, bien que ce ne soit pas important du point de vue pratique: il n'y a aucune considération de performance à prendre en compte, c'est une application cliente et ce n'est pas comme si les préférences des utilisateurs seraient récupérées des millions de fois par seconde.
Une variante de cette approche pourrait utiliser celle de Guava Optional<String>
(celle-ci est déjà utilisée dans tout le projet) au lieu d'une coutume Tuple<Boolean, String>
, ce qui permet de faire la différence entre Optional.<String>absent()
et "correct" null
. Il se sent toujours hackish, cependant, pour des raisons faciles à comprendre - l'introduction de deux niveaux de "nullité" semble abuser du concept qui sous-tendait la création de Optional
s.
Une autre option serait de vérifier explicitement si la clé existe (ajoutez une boolean containsKey(String key)
méthode et appelez getValueByKey
uniquement si nous avons déjà affirmé qu'elle existe).
Enfin, on pourrait aussi utiliser la méthode privée, mais la réalité getByKey
est un peu plus complexe que mon exemple de code.
Je vais peut-être couper les cheveux en quatre, mais je suis curieux de savoir sur quoi vous pariez être le plus proche des meilleures pratiques dans ce cas. Je n'ai pas trouvé de réponse dans les guides de style d'Oracle ou de Google.
L'utilisation d'exceptions comme dans l'exemple de code est-elle un anti-modèle ou est-elle acceptable étant donné que les alternatives ne sont pas très propres, non plus? Si c'est le cas, dans quelles circonstances cela irait-il? Et vice versa?
getValueByKey
est aussi publique.