ที่ข้อเสนอแนะของ @ amon นี่คือคำตอบที่เป็น monadic มากกว่า เป็นรุ่นที่ลวกมากซึ่งคุณต้องยอมรับสมมติฐานสองสามข้อ:
ฟังก์ชัน "unit" หรือ "return" เป็นตัวสร้างคลาส
การดำเนินการ "ผูก" เกิดขึ้นในเวลารวบรวมดังนั้นจึงซ่อนตัวจากการเรียกใช้
ฟังก์ชั่น "การกระทำ" จะถูกผูกไว้กับชั้นเรียนในเวลารวบรวม
แม้ว่าคลาสจะเป็นแบบทั่วไปและล้อมคลาส E ตามอำเภอใจ แต่ฉันคิดว่ามันเกินความจริงในกรณีนี้ แต่ฉันปล่อยไว้อย่างนั้นเป็นตัวอย่างของสิ่งที่คุณสามารถทำได้
ด้วยการพิจารณาเหล่านั้น monad แปลเป็นคลาส wrapper คล่องแคล่ว (แม้ว่าคุณจะให้ความยืดหยุ่นมากที่คุณจะได้รับในภาษาทำงานได้อย่างหมดจด):
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
สิ่งที่ยอดเยี่ยมจริงหรือ