- Operacja
szybka() potrafi tylko powiedzieć czy coś spełnia warunek:
true znaczy "na pewno spełnia"
false znaczy "nie wiadomo czy spełnia"
- Operacja
wolna() sprawdza już to na 100%:
true znaczy "na pewno spełnia"
false znaczy "na 100% nie spełnia"
Żadna z propozycji podanych w tym temacie mi się nie podoba.
Shallow, deep, heuristic, "sensitive and specific"... Ilu programistów poprawnie zrekonstruuje z tych terminów tę rozpiskę, którą podałeś powyżej? :)
"With false negatives" jest lepsze, ale rozwlekłe, wymaga chwili namysłu. Na dodatek ma wydźwięk, który - przynajmniej dla mnie - sugeruje nieprawidłowe działanie metody.
Kiedy znalezienie dobrych nazw stanowi problem, czasem warto zrobić krok do tyłu i zastanowić się, czy nie trzeba zmienić podejścia. Może problem wynika z prób upakowania trzech możliwych odpowiedzi w wartości boolean, których znaczenie zmienia się kontekstowo?
Może powinno być np. tak, że szybka metoda zwraca Optional<Boolean>. A wolna - Boolean.
Ważną informację przenosimy w ten sposób do sygnatur tych metod. Staje się oczywiste, że metoda szybka udziela odpowiedzi niepewnej. Dopilnuje tego sam silnik typów.
I odpada problem, że false miewa dwa różne znaczenia zależnie od kontekstu. Co wcześniej mogło zdezorientować.
Znalezienie nazwy staje się wtedy łatwiejsze, bo:
nie wiem jak nazwać te metody, tak żeby było z samych nazw wiadomo:
- Że
szybka() jest optymalna, ale potrafi tylko powiedzieć "na pewno tak, ale nie wiadomo czy nie".
- Że
wolna() jest zasobożerna, ale potrafi na 100% ocenić poprawność.
Od tej pory nie masz już tego "ale". Teraz nazwa musi oddać tylko pierwszą różnicę. Druga wynika z sygnatury metody.
Możliwe nazwy:
Kopiuj
Optional<Boolean> quicklyConfirm(Object o);
Boolean exhaustivelyConfirm(Object o);
A wtedy:
Kopiuj
boolean check(Object o) {
if (szybka(o)) {
return true;
}
return wolna(o);
}
Zmieni się w:
Kopiuj
boolean check(Object o) {
return quicklyConfirm(o)
.orElseGet(() -> exhaustivelyConfirm(o));
}
Wytknąć można jedno niedociągnięcie - kwestia dyskusji i gustu, czy w praktyce istotne. W praktyce quicklyConfirm może zwrócić: Optional.of(true) albo Optional.empty()*.
Rezultat Optional.of(false) jest niemożliwy. Ale to nie wynika już ani z nazwy, ani z sygnatury. Dotarliśmy do limitu tego, co może wyrazić boolean. Nawet udekorowany trójwartościowością.
Jeśli jesteśmy nieco pedantyczni i nam to przeszkadza...

...możemy pokusić się o jeszcze ściślejsze podejście.
Na przykład - używając Javy:
Kopiuj
public class ConfirmationResult {
public interface ConfirmationStatus {
Optional<Boolean> value();
}
public enum Quick implements ConfirmationStatus {
CONFIRMED,
UNKNOWN;
@Override
public Optional<Boolean> value() {
if (this == CONFIRMED) {
return Optional.of(true);
}
return Optional.empty();
}
}
public enum Exhaustive implements ConfirmationStatus {
CONFIRMED,
REJECTED;
@Override
public Optional<Boolean> value() {
return Optional.of(this == CONFIRMED);
}
}
}
I teraz:
Kopiuj
ConfirmationResult.Quick quicklyConfirm(Object o);
ConfirmationResult.Exhaustive exhaustivelyConfirm(Object o);
Oba enumy wspierają ten sam interfejs, więc mają wspólny mianownik: ConfirmationStatus, więc można tę wartość podawać - i wyciągnąć z niej Optional<Boolean> - nie interesując się kompletnie, czy jest to instancja Quick, czy Exhaustive.
A zarazem nie sposób się w żaden sposób pomylić. Wszystko jest udokumentowane na poziomie typów i definicji. if (exhaustivelyConfirm(o) == ConfirmationResult.Quick.UNKNOWN) nawet się nie zbuduje. if (quicklyConfirm(o) == ConfirmationResult.Exhaustive.REJECTED) nawet się nie zbuduje.
Można, jeśli potrzebujemy, napisać sobie nawet szybką "porównywarkę" dla instancji ConfirmationStatus, która umożliwiłaby łatwe porównania między wartościami obu enumów. Jest to Java, więc niestety wszędzie włazi nam pełno boilerplate'u. Ale z tym męczy się pół świata i na to już nie ma prostej rady.
- Na potrzeby poglądowe używam jakiejś bibliotecznej wersji Optionala, bo akurat jest dodana do projektu, który mam otwarty w IDE. Więc tak mi prościej. Your naming may vary.