views:

191

answers:

5

Putting aside, for now, the arguments about the relative virtues and disvirtues of the Singleton pattern, and considering that a Singleton is typically considered to be an instance that persists for the lifetime of an application, what would be the best way to go about having a Singleton that has a limited life?

Is there anything amiss with something like the following:

public class CategoryHandler
{    

    private static DateTime m_expires;

    public bool HasExpired
    {
        get return DateTime.Now > m_expires;
    }

    private CategoryHandler()
    {
        m_expires = DateTime.Now.AddMinutes(60);
    }

    public static CategoryHandler Instance()
    {
        if(HasExpired)
        {
            //Dispose and reconstruct
        }
        else
        {
            //Use existing instance
        }
    }

}

Or is there a much better way of approaching this problem?

+2  A: 

The only major problem that I can see is that is another class already has a reference to the old instance this won't invalidate it. So as long as all classes do this:

CategoryHandler.Instance.Method();

rather than

CategoryHandler singleton = CategoryHandler.Instance;
...
singleton.SomeMethod();

you should be fine provided you are happy that the singleton will expire the next time it is referenced rather than after exactly sixty minutes.

If you need it to expire after a period of time exactly, then you'll need to use a timer and replace the instance in the callback method (beware the timer will callback in a different thread so make sure to implement a thread safe singleton pattern)

Martin Harris
A: 

What exactly do you want to achieve with an expiring singleton? I think that you have a problem with your design if you really want to do this. And as Martin said, you will get into trouble if some code "captured" you singleton instance.

So, what exactly is your use for this? Or is the question just out of curiosity?

Maximilian Mayerl
Currently, the singleton CategoryHandler class has a List<Category> that holds a list of categories that are loaded from an xml file the first time the instance is requested. I have been asked to change this to get the categories from a database, and for the list to update immediately on each web server that's running the app. Clearly, I can force the destruction of the singleton on the same server that is updating the database but I have no way of destroying the instance on the other servers. This Singleton expiry idea is one of the possibilities I am considering.
Jibberish
@Jibberish: If you're using ASP.NET then why not use the built-in `Cache` for this?
LukeH
Luke: that's another option I have and thanks for the suggestion.
Jibberish
Or just wrap the accessor for the List<Category> in your time check, and re-load it where necessary. No need to destroy the singleton.Will there be any issues if the different nodes in the cluster are slightly out of sync for a small period of time?
chris
Only very minor issues, Chris. And I like that idea so thanks.
Jibberish
+2  A: 

You'll need some sort of locking to ensure thread-safety:

public sealed class CategoryHandler
{
    private static CategoryHandler _instance = null;
    private static DateTime _expiry = DateTime.MinValue;
    private static readonly object _lock = new object();

    private CategoryHandler() { }

    public static bool HasExpired
    {
        get
        {
            lock (_lock) { return (_expiry < DateTime.Now); }
        }
    }

    public static CategoryHandler Instance
    {
        get
        {
            lock (_lock)
            {
                if (HasExpired)
                {
                    // dispose and reconstruct _instance
                    _expiry = DateTime.Now.AddMinutes(60);
                }
                return _instance;
            }
        }
    }
}
LukeH
Indeed I do, I'm familiar with that. I think maybe I oversimplified the exmaple code!
Jibberish
+1  A: 

To avoid having the problem with classes having references to an old instance you could consider writing a caching wrapper for your class. Fist extract the interface ICategoryHandler, lets assume it looks like this:

interface ICategoryHandler 
{
  int A();
}

and then you implement the wrapper (locking omitted):

class CategoryHandlerWrapper : ICategoryHandler
{
  ICategoryHandler instance;
  private DateTime expiry = DateTime.MinValue;

  public int A()
  {
    return Instance().A();
  }

  public bool HasExpired
    {
        get return DateTime.Now > expiry;
    }

  private CategoryHandler Instance()
    {
        if(HasExpired)
        {
            //Dispose and reconstruct
        }
        else
        {
            //Use existing instance
        }
    }
}

This way you can use normal dependency injection and still enjoy the feature you are after. Also the problem with old references is encapsulated in one place.

Grzenio
+1  A: 

Have you considered using an IoC/DI Container framework and having it manage the lifetime of the "singleton"?

Microsoft's Unity is the one I'm most familiar with, and they don't provide a LifetimeManager out of the box that does exactly what you want to do. However, you can create your own descendant; see Writing Custom Lifetime Managers.

Or you could look at the other frameworks and see if one has what you want in the box.

EDIT: Note that this still won't get you out of the "captured" problem that Martin mentioned.

TrueWill