Search code examples
javadecoratorbackwards-compatibility

Using finalize() With The Decorator Pattern


I have a design issue I am trying to resolve. In short, is it ok to use finalize() to release private static resources that pertain only to that object, and are only of use for as long as that object lives? Details follow...

First here are the constraints:

  1. I am using the decorator pattern to encapsulate a type (X) that I didn't write

  2. X is final so subclassing it is out of the question.

  3. I have a method in the wrapper, say x(), that at any time will return the underlying X instance

  4. The reason for x() is that the wrapper type needs to be interchangeably compatible with existing API's that expect an X parameter

  5. The wrapper has a constructor that takes an X instance as a parameter. It then sets its encapsulated X object to be this instance.

The problem:

I want to add some functionality/data in the wrapper, BUT have it preserved. By this I mean, when the wrapper is 'unwrapped' to X, it can then be 'rewrapped' to the wrapper at some other point in the code, and hey presto, the extra data is restored even though it is not carried in the underlying X.

My thoughts so far:

If I create a static map in the wrapper class where the key is a unique X id, and the value is this extra data in some structure, then I can retrieve it inside the rewrap(X x) method let's say.

I won't use the wrapper or X object as the key in the map as this will stop it ever possibly being GC'd (unless explicitly removed from the map), so instead we'll use unique hashcodes.

Whilst this seems OK in principle, the issue is when to delete this extra data from the static map. In this case can we permit an implementation of finalize():

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

Here's my justification... We all know relying on finalize() is a bad idea to release resources in general, but here the resources in question pertain directly to the object. There is no reference to external resources, and so we need these internal resources until the wrapper object itself is GC'd, at which point we just delete the resources mapping.

The worst case scenario would be not worry about deleting these static mappings that are redundant, as this results in memory leaks.

I can't think of any other way to achieve this functionality and preserve the backwards compatibility with existing APIs:

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

So that's the problem, any alternative approaches or opinions?

Many thanks

EDIT: After further research I thought I would update this question as similar situations may be prime candidates for weak references


Solution

  • If you explicitly call Wrapper.x every time you need access to the X instance, couldn't you add a cleanup method to Wrapper and explicitly call that before getting rid of the Wrapper object?

    The cleanup method could be called from finalize too, to ensure that it gets cleaned up if it hasn't been called explicitly. This would give you the best of two worlds, as it would give you a greater chance of reducing memory leaks if the Wrapper is used incorrectly.

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

    Edit: Added code sample!