/* an Operation is a command called execute mapping Entry to String */ interface Operation { String execute(Entry e); } class NameOp implements Operation { public String execute(Entry e) { return e.getName(); } } class AddressOp implements Operation { public String execute(Entry e) { return e.getAddress(); } } class PhoneOp implements Operation { public String execute(Entry e) { return e.getPhone(); } } /* a DeptDirectory is either: the empty directory new Empty(), or the non-empty directory new Cons(Entry,DeptDirectory) */ abstract class DeptDirectory { abstract String lookUp(String key, Operation m, Operation f); String NameToAddress(String key) { return lookUp(key, new NameOp(), new AddressOp()); } String PhoneToName(String key) { return lookUp(key, new PhoneOp(), new NameOp()); } static void test() { DeptDirectory e = new Empty(); DeptDirectory d1 = new Cons(new Entry("Corky","DH 3104","x 6042"), e); DeptDirectory d2 = new Cons(new Entry("Matthias", "DH 3106", "x 5732"), d1); DeptDirectory d3 = new Cons(new Entry("Paul", "DH 3109", "x 3720"), d2); System.out.println(d1.NameToAddress("Paul")); System.out.println(d1.PhoneToName("DH 3104")); } public static void main(String[] args) { test(); } } class Empty extends DeptDirectory { String lookUp(String key, Operation m, Operation f) { return null; } } class Cons extends DeptDirectory { Entry first; DeptDirectory rest; /* constructor */ Cons(Entry f, DeptDirectory r) { this.first = f; this.rest = r; } String lookUp(String key, Operation m, Operation f) { if (key.equals(m.execute(first))) return f.execute(first); else return rest.lookUp(key,m,f); } /* accessors */ Entry getFirst() { return this.first; } DeptDirectory getRest() { return this.rest; } } class Entry { /* fields */ private String name; private String address; private String phone; /* constructor */ Entry(String n, String a, String p) { this.name = n; this.address = a; this.phone = p; } /* accessors */ String getName() { return this.name; } String getAddress() { return this.address; } String getPhone() { return this.phone; } }