VB.NET 中的单例集合






2.80/5 (10投票s)
Visual Basic .NET 中正确单例集合的示例
引言
我见过许多关于 .NET 中这个主题的文章。问题是所有这些文章都存在一些错误或遗漏。大多数文章都正确地演示了该模式,但在实际实现方面遗漏了一些重要信息。在下面的示例中,我将向您展示如何创建一个有用的单例业务对象类,该类将从数据库加载数据,将其自身持久化到应用程序中,正确地处理插入和更新,只允许自身的一个实例,并且能够重新加载。
背景
单例模式是一种设计模式,用于将类的实例化限制为一个对象。 这在 .NET Web 应用程序中非常有用。 在典型的 Web 应用程序中,每次用户请求页面时,都会将事务发送到数据库,数据库返回数据,然后将数据读入对象并显示。 如果您的站点上只有一个用户,那么这种情况发生一次,但是如果您的站点上同时有成千上万的用户,那么这种情况会发生成千上万次。 这意味着成千上万的数据库请求和成千上万的处理器时钟周期来构造和解构您的对象,所有这些都是为了完全相同的数据!
在下面的示例中,数据在第一次请求时从数据库加载,并存储在应用程序级别。 这意味着您的所有用户都将使用相同的数据,而无需不断地往返数据库。 它还考虑了更新和插入数据的需要,以及根据需要重新加载数据的能力。
Using the Code
作为基础,我们首先继承一个虚构的业务对象文章的 generic dictionary
。 我们选择 dictionary
对象是因为它允许我们按键索引到特定对象。 如果我们知道 ID,我们永远不需要循环遍历我们的集合来查找对象。
另一点需要注意的是 SyncLock
的使用,原因是可能一个用户在加载数据时另一个用户也在尝试加载。 锁只允许该代码的一个实例一次运行,所有其他实例都在队列中等待。 第二个测试将允许队列中的用户在对象加载后获取该对象。
最后,您会注意到有两个名为 editarticle
和 addarticle
的方法。 这些方法的使用会将数据插入到您的单例对象以及数据库中,因此不会强迫您重新加载您的对象,并且允许您的数据在数据库中安全可靠,为下一次重新加载做好准备。
''' <summary>
''' ArticleList
''' </summary>
''' <remarks>
''' Singleton Collection of articles
''' </remarks>
Public Class ArticleList
Inherits Generic.Dictionary(Of Integer, Aricle)
''' <summary>
''' SyncLock_LOCK
''' </summary>
''' <remarks></remarks>
Private Shared ReadOnly SyncLock_LOCK As New Object()
''' <summary>
''' Instance
''' </summary>
''' <remarks>
''' The current running instance.
''' </remarks>
Private Shared m_instance As ArticleList
Public Shared ReadOnly Property Instance() As ArticleList
Get
' initialize if not already done
If m_instance Is Nothing Then
'only allow 1 person to load data at once.
SyncLock SyncLock_LOCK
If m_instance Is Nothing Then
m_instance = LoadData()
'update time cache was loaded.
System.Web.HttpContext.Current.Application("CacheTime") = _
DateTime.Now()
End If
End SyncLock
End If
' return the initialized instance of the Singleton Class
Return m_instance
End Get
End Property
''' <summary>
''' New
''' </summary>
''' <remarks>
''' Private Constructor
''' Do not allow multiple instances of class to be created.
''' </remarks>
Private Sub New()
End Sub
''' <summary>
''' LoadData
''' </summary>
''' <remarks></remarks>
Private Shared Function LoadData() As ArticleList
Dim al As New ArticleList()
Using reader As SqlClient.SqlDataReader = _
DataAccess.ExecDataReader("sp_someprocedure")
While reader.Read
Try
'init
Dim a As New Aricle()
'load data
....
....
al.Add(a.ArticleID, a)
Catch ex As Exception
'log error and move to next row
End Try
End While
End Using
Return al
End Function
''' <summary>
''' AddArticle
''' </summary>
''' <param name="key"></param>
''' <param name="value"></param>
''' <remarks></remarks>
Public Sub AddArticle(ByVal key As Integer, ByVal value As Aricle)
'add article to collection.
MyBase.Add(key, value)
'code to insert to database goes here.
End Sub
''' <summary>
''' EditArticle
''' </summary>
''' <param name="key"></param>
''' <param name="value"></param>
''' <remarks></remarks>
Public Sub EditArticle(ByVal key As Integer, ByVal value As Aricle)
'edit in memory
m_instance(key) = value
'code to update your db goes here.
End Sub
''' <summary>
''' ReloadData
''' </summary>
''' <remarks></remarks>
Public Shared Sub ReloadData()
m_instance = Nothing
End Sub
End Class
关注点
这是一种使用 web.caching
在内存中持久化数据的好替代方法,应该可以为您的 Web 应用程序提供它所寻找的提升。 请注意,如果您尝试将 300 兆字节的内存加载到单例对象中,您的 ASP.NET 工作进程将会崩溃。 仔细设计您的应用程序,并根据您的情况做出最佳选择。