0

我想实现一个 ORM 风格的系统,当调用者不再可以访问 POJO 时,它可以保存对 POJO 的更新。

我认为引用类可以做到这一点,但它们似乎只在对象被清除后才将引用加入队列(我希望是在它们能够被收集的时候),所以一旦加入队列, .get() 方法将始终返回无效的。

我可以使用终结器,但上次我检查这些是有问题的(不能保证立即运行或根本运行)--我相信终结器和 runShutdownHook() 的组合会起作用,但这进入了相当混乱的领域。

除了强制性的“当他完成后让调用者调用 .save() ”之外,还有其他我没有想到的路径吗?

4

4 回答 4

1

使用观察者模式构建一个 ClearanceManager 和一些 Destroyables。IDestroyable 是一个用于观察者的接口,它包含方法 public void destroy() ClearanceManager 是观察者模式的主题。也许在这里使用 Singleton 来确保您的应用程序中只有一个 ClearanceManager 对象。

在 ClearanceManager 内部使用 Set(不是 List 以确保对象只能添加一次)

支持 addDestroyable(IDestroyable destoryable) 方法(可能还有 removeDestroyable 方法)。

在运行时,您需要一些析构函数仿真的类可以在 ClearenceManager 中自行注册。ClearenceManager.getInstance().addDestroyable(this);

ClearanceManager 有一个 doClearance() 方法,它应该只在 Main 方法的末尾调用。它迭代抛出私有 Set 并在每个 IDestroyable 对象上调用 destroy()。

这样做你可以模拟析构函数,而不使用它们,因为使用析构函数你正在失去对 myabe 所需对象的存在的控制。你不知道什么时候覆盖finalize,什么时候调用它。

也许,如果你不想在你的 Main 方法中调用 doClearance(),你可以在这里使用,但在这里,一个真正的析构函数 finalize()。因为 ClearenceManager 中有对所需对象的引用,所以它们不会首先被销毁。但也许 mhh,如果有交叉引用....最好不要使用 finalize,使用 doClearance() 并玩得开心:)

于 2011-03-19T01:38:08.560 回答
1

我想你在这里叫错树了。

Java 的所有基于可达性的终结器和引用机制都依赖于垃圾收集器来确定各自的对象是否可达。因此,如果您使用任何参考机制进行某种最终确定,您会遇到很多相同的问题,这些问题是finalize一个坏主意。

从技术上讲,实现自己的可达性机制是可行的;例如,通过实现您自己的特定于应用程序的引用计数。但是,它可能很昂贵、很脆弱,并使您的代码看起来很糟糕。(Java 中的引用计数可能比 C++ 中的更混乱和脆弱,因为您不能重载引用赋值运算符来确保透明地调整引用计数。所以每个引用赋值都需要包装在方法调用中。)所以我会说自己做可达性分析是个坏主意

因此,为了实用,您需要:

  • 重新考虑你的设计,这样你就不会根据可达性来做事,或者
  • 忍受使用 finalize 的后果。

第一个选项显然是最好的,IMO。

于 2011-03-19T02:37:19.517 回答
1

您是否只是想避免不得不调用save()您修改的每个 POJO?

这可以使用持久会话对象可靠地完成,如下所示:

  1. 打开一个新的会话对象。
  2. 通过会话对象加载对象。会话对象维护对其加载的所有对象的引用。
  3. 对加载的对象进行任何更改。不必对更新的对象调用保存方法。
  4. 关闭会话对象。会话保存其所有对象。保留一份干净的加载数据的副本,将其所有对象与干净的数据进行比较,并仅保存已修改的对象,这甚至可能已经足够花哨了。

如果您不想通过代码传递会话对象,您可以使用工作单元模式更进一步,将会话对象关联到当前线程:

  1. 开始一个工作单元。这会在幕后创建一个会话对象并将其与当前线程相关联。
  2. 加载对象。每当加载一个对象时,您的 ORM 会自动将它与基于当前线程的会话对象相关联。
  3. 对加载的对象进行任何更改。不必对更新的对象调用保存方法。
  4. 完成工作单元。这将关闭会话对象,保存所有对象。

这解决了基于可达性的解决方案的几个问题:

  • 您不依赖于不确定的垃圾收集,它可能在运行之间有很长的时间,或者根本不运行。
  • 在一次操作中修改的所有对象都保存在一起。如果您依赖可达性,在同一操作中修改的不同对象可能在不同时间变得不可达,这意味着您的修改可以零碎地保存到数据库中。
  • 回滚要容易得多 - 只需给您的会话对象一个 rollback() 方法。使用可达性解决方案,如果操作失败,您需要记住在每个修改的 POJO 上调用 rollback(),这实际上与您的原始问题相同。

也许请参阅http://nhibernate.info/doc/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.html或研究工作单元模式并模仿其中的一些想法。

于 2011-03-19T03:56:46.857 回答
0

也许您可以继承 PhantomReference,并在其中存储必要的数据以进行最终操作。

于 2011-03-19T01:55:35.400 回答