对象池模式 - 关注点分离 - 封装:谁负责删除实例?

时间:2015-12-08 15:52:38

标签: design-patterns abap object-pooling

场合

在开发过程中,我实现了名为object-pool-pattern的设计模式。 基本上这意味着我们的类有一个静态公共方法和一个静态保护属性。此属性包含所有实例,如果提供了某个对象键,则可以通过静态公共方法检索这些实例。 我使用一个名为get_instance的方法将实例检索到本地引用变量,然后在其上调用其他方法。 在我们的例子中,包装函数模块调用get_instance,然后在该实例上调用一些方法。在特定情况下,某个实例的生命周期结束。 因此,必须从对象池中删除它。 到目前为止,我在一个实例方法中执行此操作,其中对象从池中删除自己(表)。

假设

功能模块中的外部引用应该变为无效,因为它确实引用了一个不存在的对象。垃圾收集器现在应该携带这个孤立的引用,如果我假设正确的话。 (一般来说,这反过来说:一个未引用的对象通常被GC杀死。)在这种情况下,我仍然假设我的功能模块中的本地引用也应该被收集。因为它所引用的对象已从对象池中删除。然而,到现在为止,我仍然打电话给Free lr_myreference。 一位同事说,在调用Free lr_myreference之前,最好实现一个静态的公共方法,它不会对引用起作用,只是简单地删除池的条目。

问题

总的来说,我在考虑:谁负责从池中删除对象?那些涉及到的其他本地参考文献呢? 表中的条目(“原始参考”)?

2 个答案:

答案 0 :(得分:4)

我使用你经常描述的相同模式,最好将一些哈希表保存为工厂/经理/池类的静态属性。

就个人而言,我尽量避免需要尽可能明确地确定的对象。根据我的经验,随着应用程序变得越来越复杂,有人总是倾向于忘记最终确定。这反过来可能导致任何数量的不良副作用,这些副作用众所周知难以调试。我尝试遵循基本的假设,即垃圾收集器最好何时删除一个对象,并且一旦对象消失,就可以了。只要任何人(一个函数组,另一个类,无关紧要)保持对一个对象的引用,它仍然在使用中,并且不会被gc'ed。除了需要经常显式解构对象实例的控制框架之外,这种方法运行良好。

这种方法的明显缺点是,除非正确实施,否则对象池将趋于增长。我的实例哈希表不包含对实例的硬引用;相反,我使用CL_ABAP_WEAK_REFERENCE来跟踪托管对象。这允许垃圾收集器删除其他地方未使用的所有托管实例。当然,这也意味着您需要通过其他直接引用来跟踪您仍然需要的实例(例如,使用封装ENQUEUE/DEQUEUE调用的锁定对象,同时充当锁定令牌 - 无论谁是该对象的当前所有者也负责再次释放锁。)

警告:在广泛使用弱引用时,必须避免相当常见的结构性错误。我前段时间写过一个包含(计数器)示例的SCN article。底线:如果通过弱引用引用管理对象(在您的示例中,池类),请确保托管实例具有对管理器的硬引用 - 否则您可能会意外地得到几组托管实例代表着同样的事情。

答案 1 :(得分:2)

本质上,您暂时将对象的所有权(或至少借出)从池中转移到get_instance的调用者,因此池无法杀死对象或将其从池中删除,直到它知道新所有者已完成使用该对象。如果是,那么当前所有者可能会留下无效的对象。

因此,为了使池正确地完成其工作,您需要将对象返回到池中(或告诉它您已完成使用它),以便池可以知道当前没有使用哪些对象并且可以销毁它们安全。

我会有一个return_instance对象可以做到这一点。

如果您有多个客户端正在调用get_instance并且您正在为它们提供相同的实例,那么您将需要按引用计数进行跟踪,否则您可以将引用保留在两个列表中,一个用于可用对象,另一个用于另一个列表对于当前借出的对象,只需在调用get_instancereturn_instance时在列表之间切换。

客户不应该负责销毁对象,否则有什么意义上有游泳池?只需要一家工厂......

前一段时间我问slightly related question,这影响了我的想法