http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx
Counterview
http://www.mattberther.com/2004/05/000481.html
Here's my example
public sealed class LicenseManager : IDisposable
{
///
/// The single instance in the entire app
///
private static LicenseManager m_obLicMgr;
///
/// Single point to access all LicenseManager members
///
public static LicenseManager Instance
{
get
{
if (null == m_obLicMgr)
{
m_obLicMgr = new LicenseManager();
}
return m_obLicMgr;
}
}
Here's one that I just used.. What would the benefit be in just moving the Factory method to anothe class as Scott suggests ? Hmmm... I'll poke around.
From a TDD point of view, your sealed class now prevents the unit tests from subsituting the Singleton instance for Fake or Mock Object.
ReplyDeleteEach TDD testcase is likely to want to create new instances of the LicenceManager to ensure the testcases run separatly and cleanly.
By allowing some means of changing the number and type of licence manager, we can get the benefits of TDD whilst still 'emjoying' the benefit of the singleton.
Which basically comes down to SingleResponsability issues. In the current form the LicenceManager has two responsabilities:
1) Be a factory always return the same instance
2) Be a LicenceManager.
Separating these two responsabilities will create a more flexible design, whilst still maintaining the singleton need.
I was thinking of some points against the singleton apart from the view of testability of the code.
ReplyDeletee.g. Instead of
LicenseManager.Instance.SomeOperation()
the client now has to do
LicMgrFactory.GetInstance().SomeOperation()
I feel this has hit the readability a little bit, but let's go on
Your first point on sealing the class. I need that coz I don't want any one deriving it ever. For testability, I could add an interface but it would be required just for testing. Not an actual requirement for the system. I recently undid one of these (see my post on YAGNI interfaces on the list)
You got me on the second one though. I never thought about that one on maintaining a clean initial state. However I think I can get that one by doing this. I call Dispose() in the teardown and in the factory method I create a new instance if the member is not null OR DISPOSED. Setup and Teardown methods then take care of maintaining clean state.
Having multiple instances of LicMgr at any given point doesn't make sense for both test or production purposes. I don't think I'll ever have multiple types of LicMgr except for testing purposes. Even if I did, how would I ensure that the factory would return a single instance for real use and provide multiplicity for testing purposes.
My intent behind this post was
Is there any disadvantage to the Singleton that causes problems in design / refactoring / maintenance ? i.e. apart from the perspective of testability.
Thanks andrew, you made my brain get off the armchair and stretch for a min :)