通过单独的类在复合设计模式上实现迭代器 - 它在编程上有效吗?

Posted

技术标签:

【中文标题】通过单独的类在复合设计模式上实现迭代器 - 它在编程上有效吗?【英文标题】:Implementing an Iterator on Composite Design Pattern Through Separate Class - Is It programmatically valid? 【发布时间】:2020-01-17 16:51:15 【问题描述】:

我已经实现了复合设计模式,然后扩展了复合类以实现 Iterable,但是 iterator() 方法(它返回一个迭代器对象)也是抽象 Component 类的一部分,然后由复合类实现(但不是 Leaf 类)。

我想实现树状结构的深度优先和广度优先搜索。请参阅下面的摘要代码:

public abstract class Component 

  public void add() 
  

  public void remove() 
  

  public ArrayList<Component> getItems() 
  

  public ItemIterator iterator() 
  
public class Composite extends Component implements Iterable<Component> 

  ArrayList<Component> items = new ArrayList<Component>();
  String name;

  public ItemIterator iterator() 
  return new ItemIterator(this);
  

  public Composite(String name) 
    this.name = name;
  

  public getName() 
  // returns name
  

  public ArrayList<Component> getItems() 
  return this.items;
  
public class ItemIterator implements Iterator<Component> 

  ArrayList<Component> breadthFirstSearch = new ArrayList<Component>();
  Component currentItem;

  public ItemIterator(Component firstItem) 
  currentItem = firstItem;
  breadthFirstSearch.add(currentItem);
  

  public boolean hasNext() 
  if (breadthFirstSearch.isEmpty()) 
    return false;
  
  return true;
  

  public Component next() 
  // This method pops the root item the first time, creates its children, 
  // places at end of ArrayList,
  // then returns the root. Second time the same operations are performed
  // on the following item in the breadth first traversal of the tree.
  if (hasNext()) 
    Component nextItem = breadthFirstSearch.get(0);
    if (nextItem instanceof Composite) 
      for (Component item : currentItem.getItems()) 
        breadthFirstSearch.add(item);
      
    
    breadthFirstSearch.remove(0);
    if (hasNext()) 
      currentItem = breadthFirstSearch.get(0);
    
    return nextItem;
  
  return null;
  
public class Demo 

  public static void main(String[] args) 
    Component bag = new Composite("bag");
    Component plasticBag = new Composite("plastic bag");
    Component makeupBag = new Composite("makeup bag");
    Component phone = new Composite("phone");
    Component lipstick = new Composite("lipstick");
    Component mascara = new Composite("mascara");

    bag.add(plasticBag); bag.add(makeupBag);
    plasticbag.add(phone); makeupBag.add(lipstick); makeupBag.add(mascara);

    ItemIterator itr = bag.iterator();

    while (itr.hasNext()) 
      System.out.println(itr.next().getName());
    
  

上面的代码编译并运行良好,它工作正常。但是,我不确定它是否以编程方式可接受。它的结构似乎从根本上违背了我见过的其他迭代器实现(我在完成上述解决方案后发现的实现),但我不能完全掌握/解释它有什么问题。实现 Iterable 的另一种方式(在不同的上下文中)是以下形式:

public abstract class Component 

  public void add() 
  

  public void remove() 
  

  public ArrayList<Component> getItems() 
  

请注意上面抽象类中缺少 iterator() 方法。

public class Composite extends Component implements Iterable<Component> 

  ArrayList<Component> items = new ArrayList<Component>();
  String name;

  public Iterator<Component> iterator() 

    return new Iterator() 
      public boolean hasNext() 
      // Code
      

      public Iterator<Component> next() 
      // Code
      ;
  

  public Composite(String name) 
    this.name = name;
  

  public getName() 
  // returns name
  

  public ArrayList<Component> getItems() 
  return this.items;
  

哪种构建解决方案的方式更好,我的做法是完全错误/糟糕的做法,如果是,为什么?我是 Java 新手,所以如果这是一个不好的问题,我深表歉意。

【问题讨论】:

【参考方案1】:

我认为您描述了访问者模式:

interface Visitable 
   void accept(Visitor v);


class Visitor 
    void visit(Component c)
        c.doFooBar();// implement your logic here
    



class Component implements Visitable 

    private List<Component> children;

    void accept(Visitor v)
        v.visit(this);
        children.forEach(child -> child.accept(v)); // sumbit the visitor/iterator down the composite tree
    


public static void main(String[] args)
    Component composite = Factory.createComposite();
    composite.accept(new Visitor());

【讨论】:

【参考方案2】:

与其让迭代器建立一个待迭代的待迭代项列表,不如只存储待遍历的待处理迭代器列表。

这是Minimal, Reproducible Example:

public final class Node 
    private final String name;
    private List<Node> children = new ArrayList<>();
    public Node(String name) 
        this.name = name;
    
    public Node(String name, Node... children) 
        this.name = name;
        this.children.addAll(Arrays.asList(children));
    
    public String getName() 
        return this.name;
    
    public List<Node> getChildren() 
        return this.children;
    
    public Iterable<Node> breadthFirstSearch() 
        return () -> new NodeIterator(this, true);
    
    public Iterable<Node> depthFirstSearch() 
        return () -> new NodeIterator(this, false);
    
    @Override
    public String toString() 
        return "Node[" + this.name + "]";
    

public final class NodeIterator implements Iterator<Node> 
    private final Deque<Iterator<Node>> iterators = new ArrayDeque<>();
    private final boolean breadthFirst;
    public NodeIterator(Node node, boolean breadthFirst) 
        this.iterators.add(Collections.singleton(node).iterator());
        this.breadthFirst = breadthFirst;
    
    @Override
    public boolean hasNext() 
        return ! this.iterators.isEmpty();
    
    @Override
    public Node next() 
        Iterator<Node> iterator = this.iterators.removeFirst();
        Node node = iterator.next();
        if (iterator.hasNext())
            this.iterators.addFirst(iterator);
        if (! node.getChildren().isEmpty()) 
            if (this.breadthFirst)
                this.iterators.addLast(node.getChildren().iterator());
            else
                this.iterators.addFirst(node.getChildren().iterator());
        
        return node;
    

测试

Node root = new Node("root",
        new Node("1",
                new Node("1.1",
                        new Node("1.1.1"),
                        new Node("1.1.2")),
                new Node("1.2",
                        new Node("1.2.1"),
                        new Node("1.2.2"))
                ),
        new Node("2",
                new Node("2.1",
                        new Node("2.1.1"),
                        new Node("2.1.2")),
                new Node("2.2",
                        new Node("2.2.1"),
                        new Node("2.2.2"))));
for (Node node : root.breadthFirstSearch())
    System.out.println(node);
System.out.println();
for (Node node : root.depthFirstSearch())
    System.out.println(node);

输出

Node[root]
Node[1]
Node[2]
Node[1.1]
Node[1.2]
Node[2.1]
Node[2.2]
Node[1.1.1]
Node[1.1.2]
Node[1.2.1]
Node[1.2.2]
Node[2.1.1]
Node[2.1.2]
Node[2.2.1]
Node[2.2.2]

Node[root]
Node[1]
Node[1.1]
Node[1.1.1]
Node[1.1.2]
Node[1.2]
Node[1.2.1]
Node[1.2.2]
Node[2]
Node[2.1]
Node[2.1.1]
Node[2.1.2]
Node[2.2]
Node[2.2.1]
Node[2.2.2]

【讨论】:

@OleksandrPyrohov DOH! 是的,我知道了,谢谢你告诉我。至少我的错字是一致的,呵呵。

以上是关于通过单独的类在复合设计模式上实现迭代器 - 它在编程上有效吗?的主要内容,如果未能解决你的问题,请参考以下文章

java使用Robot类在eclipse上实现自动编写代码

在 Android 项目上实现 DAO 模式

类视图

迭代器模式

设计模式迭代器模式

C++ 适配器到底是个啥概念, 函数适配器,迭代器适配器