深入浅出设计模式(三)单例模式

来源:互联网 发布:java开发的硬件环境 编辑:程序博客网 时间:2024/06/09 23:06
          

     之前学设计模式时学过单例模式,但是没有真正用到,所以对单例的理解不深;最近在做系统时,用到了单例模式。下面来介绍一下:

     单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

      实现单例的方法有很多,我们用VB.NET的代码实现,下面我们来看几个:

1.线程不安全

    我们了解一下线程安全:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

Public NotInheritable Class Singleton    Shared m_instance As Singleton = Nothing        Private Sub New()    End Sub    Public Shared ReadOnly Property Instance() As Singleton        Get            If m_instance Is Nothing Then                m_instance = New Singleton()            End If            Return m_instance        End Get    End PropertyEnd Class

       这种方式的实现对于线程来说并不是安全的,因为在多线程的环境下有可能得到Singleton类的多个实例。如果同时有两个线程去判断(m_instance Is Nothing),并且得到的结果为真,这时两个线程都会创建类Singleton的实例,这样就违背了Singleton模式的原则。

2.线程安全

Public NotInheritable Class Singleton    Shared m_instance As Singleton = Nothing    Shared ReadOnly padlock As New Object()    Private Sub New()    End Sub    Public Shared ReadOnly Property Instance() As Singleton        Get            SyncLock padlock                If m_instance Is Nothing Then                    m_instance = New Singleton()                End If                Return m_instance            End SyncLock        End Get    End PropertyEnd Class

     这种方式的实现对于线程来说是安全的。线程在进入时先对加锁然后再检测对象是否被创建,这样可以确保只有一个实例被创建,因为在同一个时刻加了锁的那部分程序只有一个线程可以进入。这种情况下,对象实例由最先进入的那个线程创建,后来的线程在进入时(m_instence Is Nothing)为假,不会再去创建对象实例了。但是这种实现方式增加了额外的开销,损失了性能。

3.双重锁定

Public NotInheritable Class Singleton    Shared m_instance As Singleton = Nothing    Shared ReadOnly padlock As New Object()    Private Sub New()    End Sub    Public Shared ReadOnly Property Instance() As Singleton        Get            If m_instance Is Nothing Then                SyncLock padlock                    If m_instance Is Nothing Then                        m_instance = New Singleton()                    End If                End SyncLock            End If            Return m_instance        End Get    End PropertyEnd Class

       这种实现方式对多线程来说是安全的,同时线程不是每次都加锁,只有判断对象实例没有被创建时它才加锁,有了我们上面第一部分的里面的分析,我们知道,加锁后还得再进行对象是否已被创建的判断。它解决了线程并发问题,同时避免在每个 m_Instance 属性方法的调用中都出现独占锁定。它还允许您将实例化延迟到第一次访问对象时发生。实际上,应用程序很少需要这种类型的实现。大多数情况下我们会用静态初始化。

4.静态初始化

Public NotInheritable Class Singleton    Shared ReadOnly m_instance As New Singleton()    Shared Sub New()    End Sub    Private Sub New()    End Sub    Public Shared ReadOnly Property Instance() As Singleton        Get            Return m_instance        End Get    End PropertyEnd Class

      该实现与前面的示例类似,不同之处在于它依赖公共语言运行库来初始化变量。它仍然可以用来解决 Singleton模式试图解决的两个基本问题:全局访问和实例化控制。公共静态属性为访问实例提供了一个全局访问点。此外,由于构造函数是私有的,因此不能在类本身以外实例化Singleton 类;因此,变量引用的是可以在系统中存在的唯一的实例。由于Singleton实例被私有静态成员变量引用,因此在类首次被对Instance 属性的调用所引用之前,不会发生实例化。

5.延迟初始化

Public NotInheritable Class Singleton    Private Sub New()    End Sub    Public Shared ReadOnly Property Instance() As Singleton        Get            Return Nested.instance        End Get    End Property    Private Class Nested        Shared Sub New()        End Sub        Friend Shared ReadOnly instance As New Singleton()    End ClassEnd Class

    初始化工作有Nested类的一个静态成员来完成,这样就实现了延迟初始化。

 

原创粉丝点击