我可以想到三个不同的地方来检索我的单身实例,我想知道是否有任何一种方式比其他方式更好以及出于什么原因。
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
如果您也可以提出理由,那么我们将不胜感激。
答案 0 :(得分:1)
不要通过new
构造函数来实现单例。考虑Microsoft提供的EventArgs.Empty
作为传递无关紧要的事件参数的标准方法。这样做可以使单例显式使用。强制使用new
构造函数只是隐藏了实际发生的事情。
当您使用new
时,实际上应该创建一些新的内容,因为这是方法名称所暗示的内容。
Class MyClass
Public Shared ReadOnly MySingleton = New MyClass()
End Class
答案 1 :(得分:1)
何时使用Singleton模式?
当整个应用程序中只需要一个对象实例时,应使用Singleton Pattern。例如,当一个对象花费很多来实例化时,你想要传递相同的实例。
如何在整个系统中共享同一个实例?
Dependency Injection回答这一切。在您的特定方案中,您的ConcreteProductDefaultBarChart
类取决于Database
类的实例。那么为什么不通过像这样注入构造函数来使依赖变得明显呢?
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
这样,正如Mark Seemann所述:
构造函数注入的一个很好的好处是它会明显违反Single Responsibility Principle。
您可以随时更改实例生命周期,以便获得您真正想要的实例。例如,在测试环境中,您可能希望注入假数据库或模拟数据库设置以提供可预测的结果,以便您可以根据给定的结果标准测试您的代码,并查看它是否按预期运行。
如何定义单身人士?
正如您所知,Singleton在实例化对象后始终返回相同的实例。手动Singleton定义的示例可能是:
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
所以现在不仅您的班级负责为您提供实例,而且它还负责其生命周期,这更多是应用程序的责任。就我而言,一个班级永远不应对其生命周期负责。因此,让我们将此责任委托给负责创建对象实例的Factory
。
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
通过这种方式,您可以将DatabaseFactory
类注入ConcreteProductDefaultBarChart
构造函数,并通过工厂处理Database
实例生命周期,该工作负责所属,以确保它为您提供实例你打算每次需要时使用它。
最后,是的,这会增加您的代码复杂性。作为交换,使用单元测试,集成测试,功能测试和验收测试,您可以更轻松地维护代码库,并且易于排除故障并且非常易于测试。每次需要进行更改时,只需几分钟即可完成更改并查看是否通过对代码运行测试来更改更改,然后在那里进行Red-Green-Refactor会话,等等。 !
您也可以在实例生命周期中使用一些DI工具,然后您的容器负责为您处理实例,因此无需担心如何实现Singleton模式,只需告诉您的工具您想要的这个班级作为一个单身人士处理,你已经完成了!