提问人:Allain Lalonde 提问时间:9/16/2008 最后编辑:James McMahonAllain Lalonde 更新时间:10/2/2009 访问量:425
取消全局?
Doing away with Globals?
问:
我有一组深度在 20 年代的树对象。此树中的每个节点都需要访问其树的根目录。
几种解决方案:
- 每个节点都可以直接存储对根目录的引用(浪费内存)
- 我可以通过“上升”(浪费周期)在运行时计算根
我可以使用静态字段(但这相当于全局字段)
有人可以提供一种不使用全局(在任何变体中)但分别在内存或周期中比 #1 或 #2 更有效的设计吗?
编辑:由于我有一组树,我不能简单地将其存储在静态中,因为很难区分树。(感谢 Maccullt)
答:
将根作为参数传递给节点中需要它的任何函数。
编辑:选项实际上如下:
- 将根引用存储在节点中
- 根本不存储根引用
- 将根引用存储在全局
- 将根引用存储在堆栈上(我的建议,访问者模式或递归)
我认为这是所有的可能性,没有选项 5。
评论
为什么需要取消全局变量?我理解全局是坏的耻辱,但有时只是拥有一个包含所有元素的全局数据结构是最快的解决方案。
您需要做出权衡:代码清晰度和减少未来性能问题。这就是“不要优化”的意思。由于您处于优化阶段,有时有必要削减一些可读性和良好的编程实践,以支持性能。我的意思是,按位黑客是不可读的,但它们很快。
我不确定你有多少树对象,但我个人会选择选项一。除非你要处理数千+棵树,否则指针实际上不会超过几根弦。如果内存确实是一个超级重要的问题,请尝试这两种方法(它们似乎很容易实现)并通过分析器运行它。或者使用优秀的Process Explorer。
编辑:我正在开发的一个应用程序有一个包含大约 55K 节点的节点树。我们构建树结构,但也维护一个用于 O(1) 查找的数组。比使用递归 FindNodeByID 方法时得到的 O(m*n) 要好得多。
评论
点 #1 是过早的内存优化。#2 是过早的性能优化。您是否分析了您的应用以确定内存或 CPU 瓶颈是否导致您出现问题?如果不是,为什么要牺牲一个更易于维护的设计来做一个对用户没有帮助的“优化”呢?
我强烈建议您选择#2。每当你存储一些你可以计算的东西时,你所做的就是缓存。有几次缓存是个好主意,但这也是一个令人头疼的维护问题。(例如,如果通过更改节点的父节点将节点从一棵树移动到另一棵树,但忘记同时更新根字段,该怎么办?如果不需要缓存,请不要缓存。
您可以从 TreeView 派生一个类,然后添加一个单一实例静态属性。这样,您就可以有效地添加一个全局字段,该字段引用类的单个实例,但其好处是命名空间范围限定为该类。
忽略对内部类的厌恶,我可以定义一个 Tree 类并将节点定义为内部类。每个节点都可以访问其树的状态,包括其根。
这最终可能与 #1 相同,具体取决于 Java 如何将节点与其父节点相关联。(我不确定,我必须对其进行分析)
评论
通常最好将根作为参数传递。如果您使用某种迭代器来导航树,另一种方法是在其中存储对 root 的引用。
评论