当前位置:编程学习 > JAVA >>

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中还是存在 --------------------编程问答--------------------
引用 1 楼 dracularking 的回复:
还是增加和删除没有完全对应

创建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); --------------------编程问答--------------------
引用 3 楼 dracularking 的回复:
好像是加了两次,mno存在于两处

可以调试看下

换成最简单的
Persons p1 = new Persons("a");
Persons p2 = new Persons("b");
Persons p3 = new Persons("c");
 
Persons pall = new Persons("all persons");
pall.a……

确实,不过这样写只有p3是被输出了两次,但是p2并没有被输出两次。 --------------------编程问答--------------------
引用 4 楼 zhuxuanzhu 的回复:
确实,不过这样写只有p3是被输出了两次,但是p2并没有被输出两次。 

试试延展到4层,让p3.add(p4);结果更要夸张一点

a
b
c
d
d
c
d
d
d
--------------------编程问答--------------------
引用 5 楼 dracularking 的回复:
引用 4 楼 zhuxuanzhu 的回复:确实,不过这样写只有p3是被输出了两次,但是p2并没有被输出两次。 
试试延展到4层,让p3.add(p4);结果更要夸张一点

a
b
c
d
d
c
d
d
d

是的,我已经试过了,层数越多,后面的结果就越不可预测。。。简直奇葩了。。。这里的递归肯定有问题,不可尽信书啊。 --------------------编程问答--------------------
引用 6 楼 zhuxuanzhu 的回复:
引用 5 楼 dracularking 的回复:引用 4 楼 zhuxuanzhu 的回复:确实,不过这样写只有p3是被输出了两次,但是p2并没有被输出两次。 
试试延展到4层,让p3.add(p4);结果更要夸张一点

a
b
c
d
d
c
d
d
d
是的,我已经试过了,层数越多,后面的结果就越不可预测。。。简直奇葩了。。。这里的递归肯定有问……

感觉不应该发生这种问题在这种书上。

不过这种遍历法算什么呢,先序 中序 后序 都不是。 --------------------编程问答--------------------
引用 7 楼 dracularking 的回复:
引用 6 楼 zhuxuanzhu 的回复:引用 5 楼 dracularking 的回复:引用 4 楼 zhuxuanzhu 的回复:确实,不过这样写只有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本身又通过递归查看是否存在子项。。。凌乱了。 --------------------编程问答--------------------
引用 8 楼 zhuxuanzhu 的回复:
引用 7 楼 dracularking 的回复:引用 6 楼 zhuxuanzhu 的回复:引用 5 楼 dracularking 的回复:引用 4 楼 zhuxuanzhu 的回复:确实,不过这样写只有p3是被输出了两次,但是p2并没有被输出两次。 
试试延展到4层,让p3.add(p4);结果更要夸张一点

a
b
c
d
d
c
d
d
d
……

静态化后我也试过,当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,但不知道为什么实现差了 --------------------编程问答--------------------
引用 9 楼 dracularking 的回复:
引用 8 楼 zhuxuanzhu 的回复:引用 7 楼 dracularking 的回复:引用 6 楼 zhuxuanzhu 的回复:引用 5 楼 dracularking 的回复:引用 4 楼 zhuxuanzhu 的回复:确实,不过这样写只有p3是被输出了两次,但是p2并没有被输出两次。 
试试延展到4层,让p3.add(p4);结果更要夸张一点

a
b
……

确实,这段代码的思想是看懂了,但是实现就错了。应该就是hasNext的逻辑出了问题,不过就是想不出来哪里没写对。。。next函数肯定不会有错。。。 --------------------编程问答-------------------- --------------------编程问答-------------------- 这个就能解决了
补充:Java ,  Java EE
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,