Właśnie omówiłem wybór projektu po przejrzeniu kodu. Zastanawiam się, jakie są twoje opinie.
Jest ta Preferences
klasa, która jest wiadrem dla par klucz-wartość. Wartości zerowe są legalne (to ważne). Oczekujemy, że niektóre wartości mogą jeszcze nie zostać zapisane i chcemy automatycznie obsługiwać te przypadki, inicjując je z predefiniowaną wartością domyślną na żądanie.
W omawianym rozwiązaniu zastosowano następujący wzorzec (UWAGA: oczywiście nie jest to rzeczywisty kod - oczywiście jest uproszczony w celach ilustracyjnych):
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();
}
}
}
Został skrytykowany jako anty-wzór - nadużywanie wyjątków w celu kontrolowania przepływu . KeyNotFoundException
- wprowadzone w życie tylko dla tego jednego przypadku użycia - nigdy nie będzie postrzegane poza zakresem tej klasy.
Zasadniczo są to dwie metody zabawy z pobieraniem go, po prostu komunikowanie sobie czegoś.
Klucz nieobecny w bazie danych nie jest czymś niepokojącym ani wyjątkowym - spodziewamy się, że tak się stanie, ilekroć zostanie dodane nowe ustawienie preferencji, stąd mechanizm, który w razie potrzeby z wdziękiem inicjuje wartość domyślną.
Kontrargumentem było to, że getValueByKey
- metoda prywatna - jak zdefiniowano w tej chwili, nie ma naturalnego sposobu informowania metody publicznej zarówno o wartości, jak io tym, czy klucz tam był. (Jeśli nie, należy go dodać, aby można było zaktualizować wartość).
Powrót null
byłby niejednoznaczny, ponieważ null
jest to całkowicie legalna wartość, więc nie wiadomo, czy oznaczało to, że klucza nie było, czy też był null
.
getValueByKey
musiałby zwrócić jakiś a Tuple<Boolean, String>
, bool ustawiony na true, jeśli klucz już tam jest, abyśmy mogli odróżnić od (true, null)
i (false, null)
. (W języku out
C # można użyć parametru, ale to jest Java).
Czy to ładniejsza alternatywa? Tak, musiałbyś zdefiniować jakąś klasę jednorazowego użytku Tuple<Boolean, String>
, ale wtedy się pozbywamy KeyNotFoundException
, więc ten rodzaj równowagi się wyrówna. Unikamy również narzutu związanego z obsługą wyjątku, chociaż nie jest to istotne z praktycznego punktu widzenia - nie ma tu żadnych wzmianek o wydajności, jest to aplikacja kliencka i to nie tak, że preferencje użytkownika będą pobierane miliony razy na sekundę.
Odmiana tego podejścia może używać Guawy Optional<String>
(Guawa jest już używana w całym projekcie) zamiast jakiegoś niestandardowego Tuple<Boolean, String>
, a następnie możemy rozróżnić Optional.<String>absent()
i „właściwe” null
. Nadal jednak wydaje się hacking z powodów, które są łatwe do zauważenia - wprowadzenie dwóch poziomów „nieważności” wydaje się nadużywać koncepcji stojącej za tworzeniem Optional
s na pierwszym miejscu.
Inną opcją byłoby jawne sprawdzenie, czy klucz istnieje (dodaj boolean containsKey(String key)
metodę i wywołaj getValueByKey
tylko, jeśli już stwierdziliśmy, że istnieje).
Na koniec można również wstawić metodę prywatną, ale rzeczywista getByKey
jest nieco bardziej złożona niż mój przykładowy kod, więc wstawianie mogłoby sprawić, że wyglądałaby dość paskudnie.
Być może dzielę włosy tutaj, ale jestem ciekawy, na co postawiłbyś się, aby być najbliższym najlepszej praktyki w tym przypadku. Nie znalazłem odpowiedzi w przewodnikach po stylach Oracle i Google.
Czy stosowanie wyjątków, takich jak w przykładowym kodzie, jest anty-wzorcem, czy jest to dopuszczalne, biorąc pod uwagę, że alternatywy również nie są bardzo czyste? Jeśli tak, to w jakich okolicznościach byłoby dobrze? I wzajemnie?
getValueByKey
jest również publiczne.