tags:

views:

187

answers:

3

So I'm working on a middleware layer.

I'm consuming a COM DLL that deals with the low level hardware interaction, and providing an interface for the UI to do IO with the hardware.

As part of the design of my layer, we put in a contextmanager that arranges the various pieces of hardware to produce contexts that our application can work with.

So I want to guarantee that a developer that is working with my code has a single context manager to work with and then inside that context manager I can guarantee that we only allocate 1 work queue per hardware device.

Just to complicate this there is some initialization that must be done before I can start adding in hardware devices. Something that would be simple if not for the fact that typically you only access a singleton via a readonly property.

I know the singleton pattern can make alot of things difficult because of it's global accessibility. I really do not want, nor need for this class to have the global availability of a singleton, I just want the guarantee that only one will be created inside the app.

For that would I be crazy to do something like this, to basically give my singleton a constructor:

public class MySingleton
{
 private static MySingleton _MySingleton;
 private static object singletonLock = new object();

 private MySingleton(int foo1, string foo2)
 {
  //do init stuff
 }

 public static MySingleton StartSingleton(int foo1, string foo2)
 {
  try
  {
   Monitor.Enter(singletonLock);
   if (_MySingleton == null)
   {
    _MySingleton = new MySingleton(foo1, foo2);
   }
   else
    throw new Exception("Singleton already initialized");
  }
  finally
  {
   Monitor.Exit(singletonLock);
  }
  return _MySingleton;
 }

 public static MySingleton Instance
 {
  get
  {
   try
   {
    Monitor.Enter(singletonLock);
    if (_MySingleton == null)
    {
     throw new Exception("Singleton must be Initialized");
    }
   }
   finally
   {
    Monitor.Exit(singletonLock);
   }
   return _MySingleton;
  }
 }
}
+1  A: 

You wouldn't be crazy. A singleton avoids the drawbacks of global variables by virtue of being namespaced. Even though it is globally accessible via a static function call, it is not a global variable. And further, it is accessed via a namespace, so noone is likely to put it in a global var called temp, then later assign something else to temp. They should always get a local reference to it by doing

MySingleton singletonRef = MySingleton.Instance();

when their scope closes, the reference dies, and so it's not a global variable.

Zak
+2  A: 

It's not crazy code but it is a singleton anyway. If you remove Instance property then it won't be singleton anymore.

Global accessibility is not all that makes singletons nasty. What makes them nasty is that they are used all through the system directly without you being able to track all those usages. That's why it is such a nightmare in multi-threading code, that's why it is so hard to unit test anything with singletons inside.

So if it is your code I'd recommend creating just one object during application initialization and pass it around with dependency injection or as plain constructor argument. If it is a library, you can either check in constructor if it is first object being created or not and throw an exception or you can go with static constructor as you did but without Instance property, forcing developers to pass instance around.

As always, you can just create singleton, after all all it matters is that product works and customers enjoy using it, singletons or no singletons doesn't really matter.

vava
"Global accessibility is not what makes singletons nasty. What makes them nasty is that they are used all through the system directly without you being able to track all those usages"Isn't global accessibilty synonomous with untrackable usage?
Joel Barsotti
It all depends on how developer uses it. But you are right, it actually part of a problem but not the whole problem anyway.
vava
+1 - exactly. Everything gets coupled to singletons, and then becomes untestable. Note that some Dependency Injection frameworks support lifetime management, meaning you can turn any class into a singleton without the drawbacks.
TrueWill
A: 

So if I just need to garuntee that you can only create one version of my object then something like this would work:

public class MySingleton
{
    private static int objectCount = 0;
    private static object singletonLock = new object();

    public MySingleton(int foo1, string foo2)
    {
     try{
      Monitor.Enter(singletonLock);
      if (objectCount != 0)
      {
       throw new Exception("MySingleton Already exsists");
      }
      else
      {
       objectCount++;
      }
     }
     finally{
      Monitor.Exit(singletonLock);
     }

     //do initialization stuff

    }
}

obviously not a true singleton anymore.

Joel Barsotti
This is trying to be a singleton without being a singleton. Are you worried about multithreaded concurrent access, or about making sure only 1 exists at a time? It's fine to have multiple references to the same object floating around in code. It sounds like you heard somewhere "Singletons are bad" and are trying to do something about it. every single program has a single global entry point (psvm). The reason people say "Singleton's are bad" is because they get called from all over the place. So use a singleton, but don't call the method to get one from all over the place. Explicitly pass it
Zak
If I controlled both halves of the application then that would be fine.The reason why I'm trying to be so careful about picking the right design pattern is that not only may developers in my organization use this middleware layer, but other companies may likely license this IO engine to do other things with it.I'm not worried about multiple refrences, I'm simply worried about it getting abused as global storage an not being exlicitly passed around.
Joel Barsotti