使用单例模式

时间:2014-08-14 16:29:09

标签: .net vb.net oop

我可以想到三个不同的地方来检索我的单身实例,我想知道是否有任何一种方式比其他方式更好以及出于什么原因。

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

如果您也可以提出理由,那么我们将不胜感激。

2 个答案:

答案 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模式,只需告诉您的工具您想要的这个班级作为一个单身人士处理,你已经完成了!