Zgodnie z sugestią @ amon, oto odpowiedź, która jest bardziej monadyczna. Jest to bardzo uproszczona wersja, w której musisz zaakceptować kilka założeń:
funkcja „unit” lub „return” jest konstruktorem klasy
operacja „bind” ma miejsce w czasie kompilacji, więc jest ukryta przed wywołaniem
funkcje „akcji” są również powiązane z klasą w czasie kompilacji
chociaż klasa jest ogólna i obejmuje dowolną klasę E, myślę, że w tym przypadku jest to przesada. Ale zostawiłem to w ten sposób jako przykład tego, co możesz zrobić.
Biorąc pod uwagę powyższe rozważania, monada przekłada się na płynną klasę opakowania (chociaż rezygnujesz z dużej elastyczności, którą uzyskałbyś w czysto funkcjonalnym języku):
public class RepositoryLookup<E> {
private String source;
private E answer;
private Exception exception;
public RepositoryLookup<E>(String source) {
this.source = source;
}
public RepositoryLookup<E> fetchElement() {
if (answer != null) return this;
if (! exception instanceOf NotFoundException) return this;
try {
answer = lookup(source);
}
catch (Exception e) {
exception = e;
}
return this;
}
public RepositoryLookup<E> orFetchSimilarElement() {
if (answer != null) return this;
if (! exception instanceOf NotFoundException) return this;
try {
answer = lookupVariation(source);
}
catch (Exception e) {
exception = e;
}
return this;
}
public RepositoryLookup<E> orFetchParentElement() {
if (answer != null) return this;
if (! exception instanceOf NotFoundException) return this;
try {
answer = lookupParent(source);
}
catch (Exception e) {
exception = e;
}
return this;
}
public boolean failed() {
return exception != null;
}
public Exception getException() {
return exception;
}
public E getAnswer() {
// better to check failed() explicitly ;)
if (this.exception != null) {
throw new IllegalArgumentException(exception);
}
// TODO: add a null check here?
return answer;
}
}
(to się nie skompiluje ... niektóre szczegóły pozostają niedokończone, aby próbka była mała)
I wywołanie wyglądałoby tak:
Repository<String> repository = new Repository<String>(x);
repository.fetchElement().orFetchParentElement().orFetchSimilarElement();
if (repository.failed()) {
throw new IllegalArgumentException(repository.getException());
}
System.err.println("Got " + repository.getAnswer());
Pamiętaj, że możesz dowolnie komponować operacje „pobierania”. Zatrzyma się, gdy otrzyma odpowiedź lub wyjątek inny niż nie znaleziony.
Zrobiłem to naprawdę szybko; nie jest to w porządku, ale mam nadzieję, że przekazuje ten pomysł
NotFoundException
coś naprawdę jest wyjątkowego?