添加有关现有对象的其他信息的更好方法是什么?

时间:2016-04-27 07:15:38

标签: java

例如,我有一个二叉树的Node类。

public class Node {
    public Node lchild;
    public Node rchild; // public for convenience
}

现在,我有一个处理器,需要记录有关Node个实例的其他信息,而只能私下使用它们。假设预订树中的数字遍历。

我认为直接的方法是在课堂上添加一个字段:

public class Node {
    public Node lchild;
    public Node rchild;
    public int no;   // the number in the pre-order tree traverse
}

但是,我认为这绝对是一个坏主意。所以我现在使用的是:使用Map<Node, Integer>

public class MyProcessor {
    private Map<Node, Integer> no;
    public void process1(Node node) {
        int id = no.get(node); // or something like this
    }
}

当然,这可以解决问题。但我担心的是:

  1. 频繁访问地图似乎效率不高? (与添加字段方法相比)
  2. 如果我需要更多种类的信息,我需要制作更多的地图,这似乎是一场噩梦。
  3. 那么,有更好的方法吗?谢谢!

4 个答案:

答案 0 :(得分:2)

最好的解决方案可能是扩展您拥有的Node对象,这样您就可以利用新功能,同时又不会破坏现有代码。

您还可以将此与DecoratorFactory模式结合使用,以尝试透明且结构化的对象创建过程。

答案 1 :(得分:0)

这是一个关注点分离的问题。您想要添加的信息是节点还是树的处理器。

我会说,以下陈述描述了这种情况

  • 树有节点(组合聚合)
  • 节点有节点(聚合)
  • 节点有节点信息(聚合)
  • 处理器处理树(依赖)

所以我将信息与节点放在一起或关联起来。为了获得一定程度的灵活性,您可以获得Node

扩展名的信息
class ExtNode extends Node {

    int no;

}

或装饰者:

class NodeDecorator {

    Node node;
    int no;

    NodeDecorator(node){
        this.node = node;
    }
}

如果您选择地图,效率不应该是您在此阶段的关注点。访问地图非常有效。如果需要,您可以稍后进行优化。

如果添加了其他信息,您可以定义一个新结构,假设NodeInfo并将所有信息放在那里并将其放在Map或Node中而不是int。

例如

class NodeInfo {
    int no;
    String other;
}

答案 2 :(得分:0)

附加信息特定于Node层次结构的一个处理器,因此不应泄漏到节点中(关注点分离)

潜在的解决方案:

  1. 为此处理器使用并行树结构
  2. 由于Node是树结构,因此使用在访问Node结构时构建的并行结构。这个并行项(ProcessedNode?)将保存附加信息,对Node的引用以及左/右ProcessedNode子项。

    这在内存和访问方面可能更好(没有Map开销),但使处理器更复杂:它将访问ProcessedNode而不是Node。它将为下一个Node创建一个ProcessedNode,而不是访问下一个Node,并访问ProcessedNode。

    您可以延迟构建ProcessedNode,因此可以根据需要构建并行树。

    如果节点树可能会发生变异,并且您需要将ProcessedNode信息保留超过一次处理的持续时间,这是不切实际的。

    1. 使用地图
    2. 您可以在包含附加信息的类详细信息中收集所有这些信息,而不是每个附加信息都有一个地图,并使用单个地图

      该解决方案的优点是实现简单。 缺点是如果保留地图,则需要维护节点是否消失。

      最终的选择取决于需要多长时间的额外细节,如果您只需要在处理期间维护信息,那么地图将在处理结束时被删除,因此添加项目的成本没有利用地图。

      如果创建Map是切实可行的,那么在使用备用解决方案进行优化之前,您应该测量实际开销是多少:获得的收益是值得的吗?

答案 3 :(得分:0)

对于子分类方法,你应该使用&#34; getter方法&#34;用于访问子节点,以便子类可以覆盖它们。

public class Node {
    protected Node left;
    protected Node right;

    public Node(Node left, Node right) {
        this.left = left;
        this.right = right;
    }

    public Node getLeft() { return left; }
    public Node getRight() { return right; }
}

在子类中覆盖它们,在需要时懒洋洋地创建子节点。

public class DecoratedNode extends Node {
    private Node original;
    private int no = 0;

    public DecoratedNode(Node n) {
        super(null, null);
        original = n;
    }

    @Override
    public Node getLeft() {
        if (left == null && original.getLeft() != null) 
            left = new DecoratedNode(original.getLeft());
        return left; 
    }

    @Override
    public Node getRight() { 
        if (right == null && original.getRight() != null) 
            right = new DecoratedNode(original.getRight());
        return right; 
    }

    public int getNo() { return no; }
    public void setNo(int no) { this.no = no; }
}

然后将new DecoratedNode(root)传递给流程方法。