Head First 设计模式组合模式中的一个问题
今天在看head first设计模式,发现在组合模式中,有段代码有问题,是在书的第369页,我利用书中的CompositeIterator来遍历MenuComponent时候,apple pie会打印两次,个人认为是在hasNext()实现的时候,漏pop了一个迭代器。我把代码简化成另一种形式,结果发现,只要是嵌套的数据结构,那个被嵌套的对象就会被打印两次。
以下是代码:
public class TestIterator implements Iterator<Persons> {
Stack<Iterator<Persons>> iterStack = new Stack<>();
public TestIterator(Iterator<Persons> p) {
iterStack.push(p);
}
@Override
public boolean hasNext() {
// TODO Auto-generated method stub
if(iterStack.isEmpty()){
return false;
}
Iterator<Persons> iter = iterStack.peek();
if(iter.hasNext()){
return true;
}else{
iterStack.remove(iter);
return hasNext();
}
}
@Override
public Persons next() {
// TODO Auto-generated method stub
Iterator<Persons> iter=iterStack.peek();
Persons p=iter.next();
if(p.p.size()>0){
iterStack.push(p.createIterator());
}
return p;
}
@Override
public void remove() {
// TODO Auto-generated method stub
}
}
public class Persons {
public ArrayList<Persons> p=new ArrayList<>();
public void add(Persons p){
this.p.add(p);
}
public String Name;
public Persons(String name){
this.Name=name;
}
public Iterator<Persons> createIterator(){
return new TestIterator(p.iterator());
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Persons p1 = new Persons("abc");
Persons p2 = new Persons("def");
Persons p3 = new Persons("ghi");
Persons p4 = new Persons("jkl");
Persons pall = new Persons("all persons");
pall.add(p1);
pall.add(p2);
pall.add(p3);
p4.add(new Persons("mno"));
p1.add(p4);
Iterator<Persons> i = pall.createIterator();
while (i.hasNext()) {
Persons pt = i.next();
System.out.println(pt.Name);
}
}
结果显示:
abc
jkl
mno
mno
def
ghi
可以看到mno被显示了两次,我觉得是不是算法有问题,树的递归遍历变成利用iterator模式实现貌似有点难度的。求高手解答。
设计模式 数据结构 java iterator --------------------编程问答-------------------- 还是增加和删除没有完全对应
创建Iterator时每次都是新建 这样三个TestIterator就有三个iterStack 打印了mno后删除,但是在第二个TestIterator的iterstack中还是存在 --------------------编程问答--------------------
第二个iterator在栈里面没有被删除?那是不是stack.pop的判定条件不应该仅仅只是iter.next()为空么?感觉上逻辑应该没错。。试了好多次了。。 --------------------编程问答-------------------- 好像是加了两次,mno存在于两处
可以调试看下
换成最简单的
Persons p1 = new Persons("a");
Persons p2 = new Persons("b");
Persons p3 = new Persons("c");
Persons pall = new Persons("all persons");
pall.add(p1);
p1.add(p2);
p2.add(p3); --------------------编程问答--------------------
确实,不过这样写只有p3是被输出了两次,但是p2并没有被输出两次。 --------------------编程问答--------------------
试试延展到4层,让p3.add(p4);结果更要夸张一点
a
b
c
d
d
c
d
d
d
--------------------编程问答--------------------
是的,我已经试过了,层数越多,后面的结果就越不可预测。。。简直奇葩了。。。这里的递归肯定有问题,不可尽信书啊。 --------------------编程问答--------------------
感觉不应该发生这种问题在这种书上。
不过这种遍历法算什么呢,先序 中序 后序 都不是。 --------------------编程问答--------------------
他这里的递归不是树结构一般用的递归,你看他没创建一个composite iteraotor里面都还得创建一个stack,我一直觉得很奇怪,但是尝试了把stack设为静态单例,就会stack overflow。。。会无限递归一个composite iterator,永不返回false。。。他看上去就像是个完全利用栈来实现的遍历算法,栈里面存放每一层person的iterator,iterator本身又通过递归查看是否存在子项。。。凌乱了。 --------------------编程问答--------------------
静态化后我也试过,当iterStack含有如下元素时,就开始进入递归死循环了
[java.util.AbstractList$Itr@d6c16c, java.util.AbstractList$Itr@95c083, TestIterator@191d8c1]
public boolean hasNext() {
if(iterStack.isEmpty()){
return false;
}
Iterator<Persons> iter = iterStack.peek();
if(iter.hasNext()){
return true;
}else{
iterStack.remove(iter);
return hasNext();
}
}
此时的iter=TestIterator@191d8c1,通过iter.hasNext()进入递归死圈
非静态时,递归下层由于是另一个Stack实例,所含内容不同,所以没进入死循环
我想他启用Stack的初衷应该是存储某节点下所有composite iterator,但不知道为什么实现差了 --------------------编程问答--------------------
确实,这段代码的思想是看懂了,但是实现就错了。应该就是hasNext的逻辑出了问题,不过就是想不出来哪里没写对。。。next函数肯定不会有错。。。 --------------------编程问答-------------------- --------------------编程问答-------------------- 这个就能解决了
补充:Java , Java EE