我想知道是否有可能设计一个类型安全的单链表结构,这样就不可能从尾节点请求下一个节点。
同时,客户端需要能够通过node.getChild()
遍历(递归或其他)遍历列表但在编译时(至少通过人工编写的显式类型检查)阻止进行过了尾巴。
我想知道:
实现语言并不重要,但这是我正在考虑的Java示例。
在Joop的回答后编辑:
public class TestHiddenInterfaces {
interface Node { HasNoChildNode getTail(); }
interface HasNoChildNode extends Node {};
interface HasChildNode extends Node { Node getChild(); }
class HasNoChild implements HasNoChildNode {
@Override public HasNoChildNode getTail() { return this; }
}
class HasChild implements HasChildNode {
final Node child;
@Override
public Node getChild() { return child; }
HasChild(Node child) {
this.child = child;
}
@Override public HasNoChildNode getTail() {
if(child instanceof HasChild) return ((HasChild) child).getTail();
else if(child instanceof HasNoChild) return (HasNoChildNode) child;
else throw new RuntimeException("Unknown type");
}
}
@Test
public void test() {
HasNoChild tail = new HasNoChild();
assertEquals(tail, tail.getTail());
HasChild level1 = new HasChild(tail);
assertEquals(tail, level1.getTail());
HasChild level2 = new HasChild(level1);
assertEquals(tail, level2.getTail());
}
}
答案 0 :(得分:1)
在Scala中,人们使用“案例类型”进行此类输入。在Java或UML图中,人们经常看到分支和叶子之间的区别。这可以减少未使用的叶子儿的一半记忆。
类型与枚举值共存。
所以可以使用以下内容:
/**
* Base of all nodes. For the remaining types I have dropped the type parameter T.
*/
public interface Node<T> {
void setValue(T value);
T getValue();
}
public interface HasParent extends Node {
void setParent(HasChildren node);
HasChildren getParent();
}
public interface HasChildren extends Node {
void setChildren(HasParent... children);
HasPOarent[] getChildren();
}
public final class RootBranch implements HasChildren {
...
}
public final class SubBranch implements HasChildren, HasParent {
...
}
public final class Leaf implements HasParent {
...
}
public final class RootLeaf implements Node {
...
}
用法将使用重载或区分案例:
void f(Node node) {
if (node instanceof HasParent) {
HasParent nodeHavingParent = (HasParent) node;
...
}
}
我个人认为这在Java中过头了,但在Scala中,例如,类型声明是构造函数,这是有道理的:SubBranche(parent, child1, child2)
。
答案 1 :(得分:0)
这种层次结构可能存在的唯一方法是每个级别实现一个不同的接口(我在广义上使用接口而不是特定的语言术语)。
根节点无法实现getParent
- 这是您实现我能想到的编译错误的唯一方法。因此,根节点的“接口”不包括getParent
。
第一个孩子可以实现getParent
- 但是为了编译安全,他们必须返回一个类型,在编译时,它已知为根节点(即不是一种类型't 实施getParent
)。
在下一个级别,getParent
的实现必须返回一个实现getParent
的类型,该类型返回一个没有getParent
的根节点。
简而言之,即使您确实选择生成这样的实现,它也会非常脆弱,因为您需要编写不同的代码来处理层次结构的每个级别。
运行时检查 正确存在某些问题,这将是其中之一。如果每个问题都可以在编译时解决,那么每个编译的程序都只是一组结果(可能还有一个庞大的switch语句来选择你要输出的结果)