这样一个事实建议我们要采取一种更好的设计方法。
解决方法和预防措施
事实上有一个简单的办法来避免悬挂复合错误:给每个数据类型的基本例定义一个自己的类。我建议执行有着 LinkedList 类的链表,该类包含一个有 Empty 类或 Cons 类的域,而不是象我们前面做的那样,单个执行链接链表。这些类执行一个公共接口,如图 1 所示。
图 1. Empty 和 Cons UML 示意图
为了执行可变的方法,新的 LinkedList 类作为一个内部不可变的链表的容器,如清单 5 所示。这个步骤是必须的,因为真正的空链表没有域可变,所以它们是不可变的。
清单 5. 每个基本例获得自己的类
import java.util.NoSuchElementException;
public class LinkedList {
private List value;
/**
* Constructs an empty LinkedList.
*/
public LinkedList() { this.value = new Empty(); }
/**
* Constructs a LinkedList containing only the given element.
*/
public LinkedList(Object _first) { this.value = new Cons(_first); }
/**
* Constructs a LinkedList consisting of the given Object followed by
* all the elements in the given LinkedList.
*/
public LinkedList(Object _first, LinkedList _rest) {
this.value = new Cons(_first, _rest.value);
}
private LinkedList(List _value) { this.value = _value; }
public Object getFirst() { return this.value.getFirst(); }
public LinkedList getRest() { return new LinkedList(this.value.getRest()); }
public void addFirst(Object o) { this.value = new Cons(o, this.value); }
public boolean isEmpty() { return this.value instanceof Empty; }
public boolean equals(Object that) {
if (this.getClass() == that.getClass()) {
// The above test guarantees that the cast to LinkedList will always
// succeed.
return this.value.equals(((LinkedList)that).value);
}
else {
return false;
}
}
}
诊断Java代码: 悬挂复合错误类型(4)
时间:2011-02-11 IBM Eric E. Allen
那时,执行一个不可变的链表是直截了当的,如清单 6 所示。
清单 6. 对节点作加法和乘法的方法
interface List {
public Object getFirst();
public List getRest();
}
class Empty implements List {
public Object getFirst() { throw new NoSuchElementException(); }
public List getRest() { throw new NoSuchElementException(); }
public boolean equals(Object that) {
return this.getClass() == that.getClass(); }
}
class Cons implements List {
Object first;
List rest;
Cons(Object _first) {
this.first = _first;
this.rest = new Empty();
}
Cons(Object _first, List _rest) {
this.first = _first;
this.rest = _rest;
}
public Object getFirst() { return this.first; }
public List getRest() { return this.rest; }
public boolean equals(Object that) {
if (this.getClass() == that.getClass()) {
// The above test guarantees that the cast to Cons will always succeed.
Cons _that = (Cons)that;
boolean firstEltsMatch = this.getFirst().equals(_that.getFirst());
boolean restEltsMatch = this.getRest().equals(_that.getRest());
return firstEltsMatch && restEltsMatch;
}
else {
|