5

我试图找到一种方法,我可以采用二叉树类并遍历其节点,在每个节点上
执行X数量的内联操作,而无需一遍又一遍地重写相同的遍历代码。
我想如果Java允许函数指针,这对我来说会更简单......

基本上,我需要的是以下内容:

public class BinaryTreeNode {

    //...

    public void inOrderTraversalFrom(BinaryTreeNode node, /* ??? */ actions) {
        if(node.left != null)
            inOrderTraversalFrom(node.left);

        /* do something with "actions" here */

        if(node.right != null)
            inOrderTraversalFrom(node.right);
    }
}


...其中动作可以允许执行不同的方法,根据要在每个节点上执行的动作类型采用不同的参数集。

一个很好的例子是可以传递一个旨在绘制这些节点的类,接受一个 Graphics 对象作为它的参数之一,而一个类旨在执行一些不需要 Graphics 的其他一系列动作对象作为参数,而是一组完全不同的参数。

这怎么可能?执行此操作的最动态方式是什么?

4

3 回答 3

1

一种方法是:

action可以是接收 aNode并对其应用 Action 的类的实例:

public interface Action{
  public void apply(Node node){
  // To be done in the classes that will implement 
  // this interface. If it's a graphic-display of the nodes, the apply 
  // method will call draw(node.value), for example
  }
}

该行:

/* do something with "actions" here */

应该替换为

action.apply(node);

该方法的签名应更改为:

public void inOrderTraversalFrom(BinaryTreeNode node, Action action)

递归调用应该是:

inOrderTraversalFrom(node.left, action);
于 2013-03-09T04:18:12.140 回答
1

我找到了一个解决方案,虽然它可能不是最好的......

BinaryTreeNode.java:

public void inOrderTraversalFrom(BinaryTreeNode rootNode, BinaryTreeActions actions)
{
    if(rootNode.left != null)
        inOrderTraversalFrom(rootNode.left, actions);

    if(actions != null)
        actions.Perform(rootNode);

    if(rootNode.right != null)
        inOrderTraversalFrom(rootNode.right, actions);
}


BinaryTreeActions.java:

public interface BinaryTreeActions {
    public void Perform(BinaryTreeNode node);
}


BinaryTreeGraphicsActions.java:

public interface BinaryTreeGraphicsActions extends BinaryTreeActions {
    void DrawNode(BinaryTreeNode node, Graphics g);
}


BinaryTreeView.java:

private void DrawNodes(final Graphics graphics)
{
    BinaryTreeNode node = root;
    root.inOrderTraversalFrom(node, new BinaryTreeGraphicsActions() {
        @Override
        public void DrawNode(BinaryTreeNode node, Graphics g) {
            // draw the node
        }

        @Override
        public void Perform(BinaryTreeNode node) {
            DrawNode(node, graphics);
        }
    });
}


...并且任何时候你需要一组新的动作,你会为它创建一个新的界面,遵循同样的BinaryTreeGraphicsActions想法BinaryTreeView。这允许您执行任何一组操作,具体取决于您为它们设计的界面。


#EDIT: 在发现不需要 for 后,我接受了类似的答案BinaryTreeGraphicsActions,因为您可以像这样简单地使用BinaryTreeActions执行相同的内联代码:

private void DrawNodes(final Graphics graphics)
{
    BinaryTreeNode node = root;
    root.inOrderTraversalFrom(node, new BinaryTreeActions() {
        @Override
        public void Perform(BinaryTreeNode node) {
            /* draw the node, using any local vars (providing they are final) */
        }
    });
}
于 2013-03-09T04:46:20.160 回答
0

以下解决方案与此处建议的其他解决方案非常相似。但是,如果您喜欢这些东西,请使用一些设计模式结冰。

这个想法是不仅要隔离动作,还要隔离遍历。这可以通过以下两个抽象来完成。

  • 二叉树节点遍历策略
  • 二叉树节点访问者


public interface Visitable<T extends Visitor> {

  public void accept(T visitor);
}

public interface Visitor<T extends Visitable> {

  public void visit(T visitable);
}

public interface BinaryTreeNode implements Visitable<BinaryTreeNodeVisitor> {

  public void accept(BinaryTreeNodeVisitor visitor);
}

public interface BinaryTreeNodeVisitor implements Visitor<BinaryTreeNode> {

  public void visit(BinaryTreeNode visitable);
}

public interface BinaryTreeNodeTraversalStrategy {

  public void traverse(BinaryTreeNode root);
}
于 2013-03-09T05:02:55.250 回答