Я только что обсудил выбор дизайна после обзора кода. Интересно, каково ваше мнение?
Есть этот Preferences
класс, который является контейнером для пар ключ-значение. Нулевые значения допустимы (это важно). Мы ожидаем, что некоторые значения еще не могут быть сохранены, и мы хотим обрабатывать эти случаи автоматически, инициализируя их предварительно определенным значением по умолчанию при запросе.
В обсуждаемом решении использовался следующий шаблон (ПРИМЕЧАНИЕ: это не настоящий код, очевидно, он упрощен для наглядности):
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();
}
}
}
Это было раскритиковано как анти-образец - злоупотребление исключениями, чтобы управлять потоком . KeyNotFoundException
- воплощенный в жизнь только для этого одного варианта использования - никогда не будет рассматриваться вне рамок этого класса.
По сути, это два метода, которые можно использовать, просто чтобы что-то сообщить друг другу.
Ключ, отсутствующий в базе данных, не является чем-то тревожным или исключительным - мы ожидаем, что это произойдет, когда будет добавлен новый параметр предпочтения, следовательно, механизм, который изящно инициализирует его значением по умолчанию, если это необходимо.
Контраргумент состоял в том, что getValueByKey
- частный метод - как определено прямо сейчас, не имеет естественного способа информировать публичный метод как о значении, так и о наличии ключа. (Если это не так, его нужно добавить, чтобы значение могло быть обновлено).
Возвращение null
было бы неоднозначным, так null
как это совершенно законное значение, поэтому неясно, означало ли это, что ключа не было, или был null
.
getValueByKey
пришлось бы вернуть что-то вроде a Tuple<Boolean, String>
, bool установлен в true, если ключ уже существует, чтобы мы могли различать (true, null)
и (false, null)
. ( out
Параметр может быть использован в C #, но это Java).
Это хорошая альтернатива? Да, вам нужно определить какой-то одноразовый класс для эффекта Tuple<Boolean, String>
, но затем мы избавляемся от него KeyNotFoundException
, так что это уравновешивает. Мы также избегаем накладных расходов на обработку исключения, хотя это не имеет большого значения с практической точки зрения - здесь нет никаких соображений по поводу производительности, это клиентское приложение, и пользовательские настройки не будут извлекаться миллионы раз в секунду.
Вариант этого подхода может использовать Guava Optional<String>
(Guava уже используется в проекте) вместо некоторого пользовательского Tuple<Boolean, String>
, и тогда мы можем различить Optional.<String>absent()
и «надлежащий» null
. Это все еще кажется хакерским, хотя, по причинам, которые легко увидеть - введение двух уровней «нули», кажется, злоупотребляет концепцией, стоящей за созданием Optional
s в первую очередь.
Другой вариант - явно проверить, существует ли ключ (добавить boolean containsKey(String key)
метод и вызывать getValueByKey
только в том случае, если мы уже заявили, что он существует).
Наконец, можно также встроить приватный метод, но сам по себе getByKey
он несколько сложнее, чем мой пример кода, поэтому встраивание сделало бы его довольно неприятным.
Я, может быть, и тут раскалываюсь, но мне любопытно, на что бы вы поставили, чтобы быть ближе к наилучшей практике в этом случае. Я не нашел ответа в руководствах по стилю Oracle или Google.
Является ли использование исключений, как в примере кода, антипаттерном, или это приемлемо, учитывая, что альтернативы тоже не очень чисты? Если да, то при каких обстоятельствах это будет хорошо? Наоборот?
getValueByKey
также является публичным.