@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
、実際に例外的である何かが?