使用装饰模式的finalize()

时间:2013-01-03 10:55:21

标签: java decorator backwards-compatibility

我有一个我想解决的设计问题。简而言之,是否可以使用finalize()来释放仅与该对象相关的private static资源,并且仅在该对象存在时才使用?细节如下......

首先是约束:

  1. 我正在使用装饰器模式来封装我的类型(X) 没有写

  2. X final 因此无法对其进行子类化。

  3. 我在包装器中有一个方法,比如x(),在任何时候都会这样 返回基础X instance

  4. x()的原因是包装类型需要 可互换地兼容期望X的现有API 参数

  5. 包装器有一个构造函数,它将X实例作为一个 参数。然后它将其封装的X对象设置为此 实例

  6. 问题:

    我想在包装器中添加一些功能/数据,保留它。我的意思是,当包装器“展开”到X时,它可以在代码中的某个其他位置被“重新包装”到包装器,并且嘿presto,额外的数据即使它是没有载入基础X

    到目前为止我的想法:

    如果我在包装器类中创建一个静态映射,其中键是唯一的X id,并且值是某个结构中的额外数据,那么我可以在rewrap(X x)方法中检索它让我们说吧。

    我不会使用包装器或X对象作为地图中的键,因为这会阻止它可能是GC(除非从地图中明确删除),所以我们将使用唯一散列码。

    虽然原则上这似乎没问题,但问题是何时从静态地图中删除这些额外的数据。在这种情况下,我们是否允许执行finalize():

    finalize(){
       map.remove(wrapperKey);
    }
    

    这是我的理由......我们都知道依赖于finalize()一般来说释放资源是一个坏主意,但这里的资源直接与对象有关。没有对外部资源的引用,因此我们需要这些内部资源,直到包装器对象本身为GC,此时我们只删除资源映射。

    最糟糕的情况是不必担心删除这些冗余的静态映射,因为这会导致内存泄漏。

    我想不出任何其他方法来实现此功能并保持与现有API的向后兼容性:

    public void foo(Wrapper wrapper){
      bar(wrapper.x());
    }
    public void bar(X instance){...}
    

    那就是问题,任何替代方法或意见?

    非常感谢

    修改 经过进一步的研究后,我想我会更新这个问题,因为类似的情况可能是weak references

    的主要候选人

1 个答案:

答案 0 :(得分:0)

如果您每次需要访问X实例时都显式调用Wrapper.x,那么您是否无法在Wrapper中添加清理方法并在删除Wrapper对象之前显式调用它?

也可以从 finalize 调用清理方法,以确保在未明确调用的情况下清理它。这将为您提供两个世界中最好的,因为如果错误地使用Wrapper,它将为您提供更大的减少内存泄漏的机会。

void someRandomMethod() {
    Wrapper someWrapperINeed = new Wrapper(new X(blah, blah blah));
    foo(someWrapperINeed);
    someWrapperINeed.clean();

    // Instead of foo(new Wrapper(new X(blah, blah, blah));
}

// Or foo can call clean if the wrapper will never be needed after its invocation
void foo(Wrapper w) {
    bar(w.x());
    w.clean();
}

编辑:添加了代码示例!