Reputation: 945
I can think of three different places to retrieve the instance of my singleton, I am wondering if any one way is better than the others and for what reason.
Friend Class ConcreteProductDeafultBarChart
Implements IAbstractBarChart
Private Way1 As DatabaseSingleton = DatabaseSingleton.Instance
Private Way2 As DatabaseSingleton
Public Sub New()
Way2 = DatabaseSingleton.Instance
End Sub
'This function gets called else where often
Public Function GetBarChartData() As System.Data.DataTable Implements IAbstractBarChart.GetBarChartData
Dim Way3 As DatabaseSingleton = DatabaseSingleton.Instance
'Do something with my singleton instance
End Function
End Class
If you can give your reasons behind your claim too, it would be appreciated.
Upvotes: 0
Views: 1088
Reputation: 24132
When to use the Singleton Pattern?
One shall use the Singleton Pattern when only an instance of an object is required throughout the application. For instance, when an object costs much to instantiate, you want to pass the same instance along.
How to share the same instance across the whole system?
Dependency Injection answers it all. In your particular scenario, your ConcreteProductDefaultBarChart
class depends on an instance of the Database
class. So why not make the dependency obvious by injecting into its constructor like so?
Friend Class ConcreteProductDefaultBarChart
Implements IAbstractBarChart
Public Sub New(Database database)
If database Is Nothing Then Throw New ArgumentNullException("database")
Me.database = database
End Sub
Private ReadOnly database As Database
End Class
This way, as already stated by Mark Seemann:
One of the wonderful benefits of Constructor Injection is that it makes violations of the Single Responsibility Principle glaringly obvious.
And you may change your instance lifecycle whenever you want so that you get the instance you really intend to. For instance, in a testing context, you might as well want to inject a fake database or a mocked database setup to give predictable results so that you may test your code against given result criterion, and see if it behaves as wanted.
How to define a Singleton?
A Singleton, as you already know, always return the same instance once your object is instantiated. An example of a manual Singleton definition might be:
Public NotInheritable Class Database
Private Sub New()
End Sub
Public ReadOnly Property Instance() As Database
Get
If db Is Nothing Then db= New Database()
Return db
End Get
End Property
Private db As Database
End class
So now not only your class is responsible to provide you with an instance, but it is also responsible for its lifecycle, which is more the application responsibility. A class, as far as I'm concerned, shall never be responsible for its lifecycle. So let's delegate this responsiblity to a Factory
which is responsible to create instances of objects.
Public Class DatabaseFactory
Public Sub New()
End Sub
Public Function Create(ByVal connectionString As String) As Database
If String.IsNullOrWhiteSpace(connectionString) Then
Throw New ArgumentNullException("connectionString")
End If
If database Is Nothing Then database = New Database(connectionString)
Return database
End function
Private Shared database As Database
End Class
This way, you may inject your DatabaseFactory
class into your ConcreteProductDefaultBarChart
constructor, and handle your Database
instance lifecycle through your factory which responsility belongs to make sure it provides you with the instance you intended to use each time you need it.
In the end, yes it increases your code complexity. In exchange, you get an easier to maintain code base with easy-to-troubleshoot and very easy-to-test application using unit tests, integration tests, functional tests and acceptance tests. And each time a change is required, you only need a few minutes to bring the changes and see whether they are breaking changes or not by running the tests against your code, then there you go for a Red-Green-Refactor session, et voilà!
You may as well use some DI tools out there for your instances lifecycle, then your container is responsible to handle your instances for you, so no need to worry how to implement the Singleton pattern anymore, just tell your tool that you want this class handled as a Singleton, and you're done!
Upvotes: 1
Reputation: 6790
Don't get attached to implementing the singleton via the new
constructor. Consider the EventArgs.Empty
that Microsoft provides as a standard way to pass insignificant event arguments. Doing it this way makes the use of the singleton explicit. Forcing the use of the new
constructor just conceals what is actually happening.
When you use new
something new should actually be created since that's what the method name implies.
Class MyClass
Public Shared ReadOnly MySingleton = New MyClass()
End Class
Upvotes: 1