2

I want to use flyweight pattern to return the same instance of my object each time.

public class ThingFactory {
  private static final HashMap<UUID, Thing> things = new HashMap<>();

  public static Thing getThing(UUID id) {
    Thing thing = things.get(id);

    if (thing == null) {
      thing = new Thing(id);
      things.put(id, thing);
    }

    return thing;
  }
}

This approach has the drawback that things will contain a reference to each Thing object, even if the object will not be needed any more. So the garbage collector cannot automatically identify and destroy those objects.

How can I destroy the stored reference though when I know there are no other references to it anymore?

  • 3
    Use a WeakHashMap – David Arno Apr 29 at 13:42
  • 3
    With flyweights, what's the point of destroying any of them before termination? The very point of flyweights is that you might need this exact object again if another get() comes in. – Kilian Foth Apr 29 at 13:43
  • 1
    Leave the caching for the cache... – Laiv Apr 29 at 14:00
  • 3
    The cache is an index. It indexes things from execution to execution for their later reuse. All of this without forcing you to adopt any specific design. Flyweights imply design since you have to divide elements by their most common and heavy parts so that they are calculated only once during the execution and shared by all the objects that need it (we usually have many of them). It doesn't mean that this common part should be "remembered" from execution to execution. The OP didn't implement Flyweight. It just implemented a very simple cache. – Laiv Apr 29 at 14:27
  • 2
    This is Flyweight HeavyThing heavyThing = new HeavyThing(); ... for(int i=0; i < 60000; i++) LightThing lightThing = new LightThing(heavyThing); Then you can cache the HeavyThing or not for the next execution (threat, whatever) – Laiv Apr 29 at 15:05
0

Leaving aside the question of what exactly the flyweight pattern is and if this is it, you kinda answer your own question.

How can I destroy the stored reference though when I know there are no other references to it anymore?

Keep track of the references and remove it when there are none left

in c# you could use IDisposable to prompt the user to dispose of resources when they are finished and overwrite the methods to keep track of your objects.

in java I think you can do something similar with AutoCloseable

https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html

When you get the object from the ThingFactory increment a counter and when close() is called on the object decrement the counter, and remove if its zero

  • 1
    in c# you could use IDisposable to prompt the user to dispose of resources -- Eh, that's how a lot of people read IDisposable, but that's not really a satisfactory definition of the interface. Microsoft's official line is that IDisposable is used to clean up unmanaged resources, but that's not a satisfactory definition either; IDisposable is routinely abused to do things like close HTML tags and other things. – Robert Harvey Apr 29 at 15:37
  • yeah, using dispose to close html tags was a terrible use of IDisposable, but hey ho. The point is people know you are supposed to call dispose and use 'using' which automatically calls dispose. and in this case the cached/flyweight is the resource you want to free up (for whatever reason) – Ewan Apr 29 at 15:43
  • the WeakHashSet suggestion in the comment seems like a nice easy suggestion. Why is this answer better ? – theonlygusti Apr 29 at 20:07
  • I dont see how the weakhashmap will work tbh. maybe @davidarno can expand? – Ewan Apr 29 at 20:10
  • 1
    Aren't you just re-inventing reference counting/mark and sweep garbage collection, poorly? – Robert Harvey Apr 30 at 17:42
0

Here's the simple solution (untested):

public class ThingFactory {
  private static final HashMap<UUID, WeakReference<Thing>> things = new HashMap<>();

  public static Thing getThing(UUID id) {
    WeakReference<Thing> ref = things.get(id);
    Thing thing;

    if (ref == null || (thing = ref.get()) == null) {
      thing = new Thing(id);
      ref = new WeakReference<Thing>(thing);
      things.put(id, ref);
    }

    return thing;
  }
}

There are some tweaks to this that you might consider. In my experience/recollection, the WeakReferences are cleared aggressively by GC so you might find that you aren't getting much value from the flyweight i.e. each object gets used once and then GC'd. This will depend on usage patterns so YMMV.

A way to deal with that is to keep both a normal reference and a weak reference and then periodically check for WeakReferences that have been cleared. Then you can use some logic to determine whether the main reference should be cleared. For example you could have something like this:

private static class RefPair {
  final Thing thing;
  final WeakReference<Thing> ref;
  final long created = System.currentTimeMillis();

  RefPair(Thing thing) {
    this.thing = thing;
    this.ref = new WeakReference<>(thing);
  }

  boolean expired()
  {
    if (ref.get() != null) return false;

    return (System.currentTimeMillis() - created) > EXPIRATION;
  }
}

And remove the value from the map once expired() returns true.

Which would allow you to guaranteed that each flyweight will live for at least EXPIRATION millis.

You might also want to take some time to get a handle on using ReferenceQueue because it can help with these kinds of things. For example, in this case you could use the ref-queue to inform determine which references have been cleared. You will need to understand how to use a ReferenceQueue if want to use PhantomReferences. A PhantomReference is actually more appropriate for this expiration solution. If you are interested, I can show you how that looks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.