Consider again the familiar problem of computing a String representation of an IList that displays a comma-separated list of its elements delimited by a pair of matching parentheses. We have seen at least one way to compute such a String representation using a visitor called ToStringAlgo. Below are three different algorithms, ToString1, ToString2 and ToString3, that compute the same String representation.
Main Visitor ToString1 |
Tail-recursive helper ToString1Help |
package listFW.visitor;
import listFW.*;
public class ToString1 implements IListAlgo {
public static final ToString1 Singleton = new ToString1();
private ToString1() {
}
public Object emptyCase(IMTList host, Object... nu) {
return "()";
}
public Object nonEmptyCase(INEList host, Object... nu) {
return host.getRest().execute(ToString1Help.Singleton,
"(" + host.getFirst());
}
}
|
/**
* Helps ToString1 compute the String representation of the rest of the list.
* It takes as input the accumulated string representation of the preceding
* list. This accumulated string contains the left most parenthesis and all
* the elements of the preceding list, each separated by a comma.
*/
class ToString1Help implements IListAlgo {
public static final ToString1Help Singleton = new ToString1Help();
private ToString1Help() {
}
public Object emptyCase(IMTList host, Object... acc) {
return acc[0] + ")";
}
public Object nonEmptyCase(INEList host, Object... acc) {
return host.getRest().execute(this, acc[0] + ", "
+ host.getFirst());
}
}
|
Main Visitor ToString2 |
Tail-recursive helper ToString2Help |
package listFW.visitor;
import listFW.*;
public class ToString2 implements IListAlgo {
public static final ToString2 Singleton = new ToString2();
private ToString2() {
}
public Object emptyCase(IMTList host, Object... nu) {
return "()";
}
public Object nonEmptyCase(INEList host, Object... nu) {
return host.getRest().execute(ToString2Help.Singleton,
host.getFirst().toString());
}
}
|
/**
* Helps ToString2 compute the String representation of the rest of the list.
*/
class ToString2Help implements IListAlgo {
public static final ToString2Help Singleton = new ToString2Help();
private ToString2Help() {
}
public Object emptyCase(IMTList host, Object... acc) {
return "(" + acc[0] + ")";
}
public Object nonEmptyCase(INEList host, Object... acc) {
return host.getRest().execute(this,
acc[0] + ", " + host.getFirst());
}
}
|
Main Visitor ToString3 |
Non tail-recursive helper ToString3Help |
package listFW.visitor;
import listFW.*;
public class ToString3 implements IListAlgo {
public static final ToString3 Singleton = new ToString3();
private ToString3() {
}
public Object emptyCase(IMTList host, Object... nu) {
return "()";
}
public Object nonEmptyCase(INEList host, Object... nu) {
return "(" + host.getFirst()
+ host.getRest().execute(ToString3Help.Singleton);
}
}
|
/**
* Helps ToString3 compute the String representation of the rest of the list.
*/
class ToString3Help implements IListAlgo {
public static final ToString3Help Singleton = new ToString3Help();
private ToString3Help() {
}
public Object emptyCase(IMTList host, Object... nu) {
return ")";
}
public Object nonEmptyCase(INEList host, Object... nu) {
return ", " + host.getFirst()
+ host.getRest().execute(this);
}
}
|
What makes each of the above different from one another is its helper visitor. Each helper defined in the above will only perform correctly if it is passed the appropriate parameter. In a sense, each helper is an implementation of the main visitor. We should hide each of them inside of its corresponding main visitor to ensure proper usage and achieve full encapsulation of the main visitor.
- 1319 reads