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

Design patterns 对象池模式-关注点分离-封装:谁负责删除实例?,design-patterns,abap,object-pooling,Design Patterns,Abap,Object Pooling,形势 在开发过程中,我实现了名为对象池模式的设计模式。 基本上这意味着我们的类有一个静态公共方法和一个静态保护属性。此属性携带所有实例,如果提供了某个对象键,则静态公共方法可以检索这些实例。 我使用一个名为get_instance的方法将实例检索到本地引用变量中,然后对其调用其他方法。 在我们的例子中,包装函数模块调用get_instance,然后在该实例上调用一些方法。在特定情况下,某个实例的生存期结束。 因此,必须将其从对象池中删除。 直到现在,我都是在一个实例方法中完成的,对象从池(表)中

形势

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

假设

函数模块中的外部引用应已无效,因为它引用的对象不存在。如果我假设正确的话,垃圾收集器现在应该携带这个孤立引用。(通常情况下,情况正好相反:未引用的对象通常会被GC终止。)在这种情况下,我仍然认为我的函数模块中的本地引用也应该被收集。因为它所引用的对象已从对象池中删除。尽管如此,直到现在,我仍然称之为免费lr\u myreference。 一位同事说,在调用
Free lr\u myreference
之前,最好实现一个静态公共方法,它不会对引用执行操作,而只是终止池的入口

问题

一般来说,我在想:谁负责从池中删除对象?其他当地参考文献中提到的
表中的条目(“原始引用”)?

本质上,您是将对象的所有权从池中临时转移(或至少借出)给
get\u instance
的调用者,因此池在知道新所有者已使用完对象之前无法杀死对象或将其从池中移除。如果是这样,则当前所有者可能会留下一个无效对象

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

我将有一个
return\u实例
对象来执行此操作

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

客户端不应该负责销毁对象,否则拥有池有什么意义?只要有一个工厂就好了


不久前我问过,这影响了我的思考

我使用了与您经常描述的模式相同的模式,最好是将一些哈希表作为factory/manager/pool类的静态属性保存

就我个人而言,我尽可能避免需要明确确定的对象。根据我的经验,随着应用程序变得越来越复杂,总会有人忘记最后定稿。这反过来可能会导致许多众所周知难以调试的不良副作用。我试图遵循这样一个基本假设,即垃圾收集器最清楚何时删除对象,并且一旦对象消失,就只剩下这些了。只要任何人(一个函数组,另一个类,不重要)保留对对象的引用,它就仍然在使用中,不会被gc’ed。除了控制框架之外,在控制框架中,您需要经常显式解构对象实例,这种方法工作得相当好

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


注意:广泛使用弱引用时,必须避免一个相当常见的结构错误。我不久前写了一篇文章,其中包含一个(反)示例。一句话:如果管理对象(在您的示例中,池类)是通过弱引用引用的,请确保托管实例具有对管理器的硬引用,否则您可能会意外地得到多组代表同一事物的托管实例。

据我所知,客户机借出了该实例,但它在同一个系统上起作用。也就是说,如果我的本地引用变量将更改任何属性值,则池表中的对象也将更改其值,因为客户端在池表中引用此对象。那么,为什么需要创建“return\u instance”呢?您需要返回实例,以便池知道何时可以安全地调用
Dispose()
(或任何清理方法)。客户端无法调用clean-up方法,因为池仍将有一个引用,并且可能希望重用该对象。如果客户正在处理,那么您没有