【发布时间】:2012-02-03 10:32:12
【问题描述】:
我负责维护一个用 Swing 编写的旧应用程序,以及一个用 Java3D 编写的类似 CAD 的工具。我们遇到了内存使用问题。分析后,这与应用程序中的撤消功能有关。
所有撤消功能都是基于状态的,基本概念如下:
public class UndoAction {
private UndoTarget target;
private Object old_data;
private Object new_data;
}
创建这些 UndoAction 的代码基本上散布在整个应用程序中。因为新对象的修改、现有对象的修改和子树的修改之间没有区别,所以会发生以下情况:
发生的情况是单个动作如下:
- 创建一个新对象
A。 - 修改对象的字段
foo。一个新的 UndoAction 被放置在堆栈上,其中包含 foo_old 和 foo_new。 - 修改对象的字段
bar。一个新的 UndoAction 被放置在堆栈上,其中包含 bar_old 和 bar_new。 - 执行
B.setField(A)。一个新的 UndoAction 被放置在堆栈上,其中包含 field_old 和 field_new (== A)。
对此根本没有粒度或任何控制。这对可维护性毫无帮助。
我想重构这个系统,使它变得可维护和内存友好。不幸的是,使用命令模式实现撤消系统是不可能的。这些行动影响太大而无法恢复。我想实现以下内容:
- 使用注释提供“撤消分界”。 @Undoable() 会将一个方法标记为生成一个 UndoAction 并将其放入堆栈。这可以像事务一样进行参数化:REQUIRE、NEST、JOIN... 在进入 Undoable 方法时会克隆完整的对象图。
- 当事务(=方法)完成时,算法应将新状态与旧状态进行比较并保存差异。
- 要实现这一点,我们可以使用 AOP。这使我们能够保持核心代码非常干净。
现在,我的问题: Java 中是否已经存在上述 3 个功能中的任何一个?我可以想象我不是第一个与基于状态的撤消以及与之相关的问题(撤消划分、状态比较......)搏斗的人
【问题讨论】:
-
AspectJ 非常强大,它可能适用于您想做的事情。
-
addFirst()超过一定限制时不能使用 Deque 和 removeLast() 吗? -
UndoStack 的准确实现并不难; Swing UndoManager 对我来说做得很好。困难在于构造 oldState 和 newState:要克隆什么,何时将其添加到新的 UndoAction 以及如何确保旧数据不会在某处被引用。
标签: java swing aop undo java-3d