Java 将finalize()与Decorator模式一起使用

Java 将finalize()与Decorator模式一起使用,java,decorator,backwards-compatibility,Java,Decorator,Backwards Compatibility,我正试图解决一个设计问题。简而言之,可以使用finalize()来释放仅与该对象相关且仅在该对象存在时可用的私有静态资源吗?详情如下 首先是限制条件: 我正在使用decorator模式封装一个类型(X) 我没有写信 X是最终版,因此不可能对其进行子类化 我在包装器中有一个方法,比如说x(),它在任何时候都会 返回基础X实例 之所以使用x(),是因为包装器类型需要 可与预期为X 参数 包装器有一个构造函数,它将X实例作为 参数然后将其封装的X对象设置为 例如 问题是: 我想在包装器中添加一些功能/

我正试图解决一个设计问题。简而言之,可以使用
finalize()
来释放仅与该对象相关且仅在该对象存在时可用的
私有静态资源吗?详情如下

首先是限制条件:

  • 我正在使用decorator模式封装一个类型(
    X
    ) 我没有写信

  • X
    最终版
    ,因此不可能对其进行子类化

  • 我在包装器中有一个方法,比如说
    x()
    ,它在任何时候都会 返回基础
    X实例

  • 之所以使用
    x()
    ,是因为包装器类型需要 可与预期为
    X
    参数

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

  • 问题是:

    我想在包装器中添加一些功能/数据,但要保留它。我的意思是,当包装被“取消包装”到
    X
    时,它可以在代码中的其他某个点被“重新包装”到包装,并且,即使额外的数据没有在底层
    X
    中携带,也会被恢复

    到目前为止,我的想法是:

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

    我不会使用包装器或
    X
    对象作为映射中的键,因为这将阻止它可能被GC'd(除非从映射中显式删除),因此我们将使用唯一的hashcode

    虽然这在原则上看起来还可以,但问题是何时从静态映射中删除这些额外数据。在这种情况下,我们可以允许finalize()的实现:

    这是我的理由。。。我们都知道,通常依赖finalize()来释放资源是个坏主意,但这里讨论的资源直接与对象相关。没有对外部资源的引用,因此我们需要这些内部资源,直到包装器对象本身被GC’d,在这一点上,我们只是删除资源映射

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

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

    public void foo(Wrapper wrapper){
      bar(wrapper.x());
    }
    public void bar(X instance){...}
    
    这就是问题所在,有其他的方法或观点吗

    非常感谢

    编辑:
    在进一步研究之后,我想我会更新这个问题,因为如果每次需要访问x实例时都显式调用Wrapper.x,那么类似的情况可能是

    的主要候选情况,那么您不能向Wrapper添加一个cleanup方法,并在除去Wrapper对象之前显式调用它吗

    也可以从finalize调用cleanup方法,以确保在未显式调用它时将其清除。这将为您提供两个世界中最好的一个,因为如果包装器使用不当,您将有更大的机会减少内存泄漏

    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();
    }
    

    编辑:添加代码示例

    我刚刚编辑了这个问题,因为我不够清晰,很抱歉。额外的数据直接与X实例关联,因此需要保留这些数据,以防以后重新包装未包装的X实例。因此,我无法处理x()中的额外数据。wrapperKey是否与x实例相关?这样,您就可以查找额外的数据,并通过了解X来重新创建包装器对象?在这种情况下,为什么不直接使用X对象作为关键点?你怎么能从包装器的finalize方法中删除额外的数据呢?那么在重新创建包装器之前,您可能会丢失数据。这是一个很好的观点。密钥需要直接与X相关,因为包装器是一次性的,可以随时重新创建。在本例中,删除这些额外数据需要在X的finalize中完成,因为包装器不知道这是否是X最后一次包装。六羟甲基三聚氰胺六甲醚。。。有没有想过用另一种方法来实现同样的目标?是否只有“遗留”代码可以控制X何时被处理?您是否可以监听某种事件,以便能够在适当的时间处理包装器中的数据?需要X实例的类是否可以子类化?包装器是位于现有API之上的层/插件的一部分。令人沮丧的是,没有任何回调可以连接到。。。看起来我能做的最好的事情就是将额外的数据存储在包装器中,而不是保存它。或者让客户负责处理额外的数据。。但这可能有点不友好?
    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();
    }