На пропозицію @ amon, ось відповідь, яка більш монадійна. Це дуже зруйна версія, де ви повинні прийняти кілька припущень:
функція "одиниця" або "повернення" - це конструктор класів
операція "прив'язування" відбувається під час компіляції, тому вона прихована від виклику
функції "дії" також прив'язані до класу під час компіляції
хоча клас є загальним і охоплює будь-який довільний клас E, я думаю, що це насправді в цьому випадку непосильне. Але я залишив це саме як приклад того, що ти міг зробити.
З урахуванням цих міркувань, монада перекладається на вільний клас обгортки (хоча ви відмовляєтеся від більшої гнучкості, яку ви отримаєте на чисто функціональній мові):
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;
}
}
(це не буде компілюватися ... певні деталі залишаються незавершеними, щоб зберегти зразок малим)
І виклик виглядатиме так:
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());
Зауважте, що у вас є гнучкість складати операції "отримання", як вам подобається. Він зупиниться, коли отримає відповідь або виняток, відмінний від не знайденого.
Я зробив це дуже швидко; це не зовсім правильно, але, сподіваємось, передає ідею
NotFoundException
щось насправді виняткове?