현재, 몸담고 있는 회사의 솔루션 코드를 보다가 이런 것을 발견했다.
Imports System.Threading
Public Class Metadata
Private myMetadata As New InsightMetadata
Private Shared _singleton As Metadata
Private Shared myInstanceMutex As New Mutex
Private Sub New()
End Sub
Public Shared Function GetInstance() As Metadata
myInstanceMutex.WaitOne()
Try
If _singleton Is Nothing Then
_singleton = New Metadata
End If
Finally
myInstanceMutex.ReleaseMutex()
End Try
Return _singleton
End Function
Public ReadOnly Property Appset(ByVal appsetID As String, ByVal app As String, ByVal userName As String, ByVal context As String, ByVal security As String) As Appset
Get
If (IsNothing(myMetadata.Appset(appsetID))) Then
load(appsetID, app, userName, context, security)
End If
Return myMetadata.Appset(appsetID)
End Get
End Property
Public Overloads Sub refresh(ByVal appset As String, ByVal app As String, ByVal userName As String, ByVal context As String, ByVal security As String)
load(appset, app, userName, context, security)
End Sub
Private Function load(ByVal appsetID As String, ByVal app As String, ByVal userName As String, ByVal context As String, ByVal security As String) As Appset
...
End Function
End Class
Public Class Metadata
Private myMetadata As New InsightMetadata
Private Shared _singleton As Metadata
Private Shared myInstanceMutex As New Mutex
Private Sub New()
End Sub
Public Shared Function GetInstance() As Metadata
myInstanceMutex.WaitOne()
Try
If _singleton Is Nothing Then
_singleton = New Metadata
End If
Finally
myInstanceMutex.ReleaseMutex()
End Try
Return _singleton
End Function
Public ReadOnly Property Appset(ByVal appsetID As String, ByVal app As String, ByVal userName As String, ByVal context As String, ByVal security As String) As Appset
Get
If (IsNothing(myMetadata.Appset(appsetID))) Then
load(appsetID, app, userName, context, security)
End If
Return myMetadata.Appset(appsetID)
End Get
End Property
Public Overloads Sub refresh(ByVal appset As String, ByVal app As String, ByVal userName As String, ByVal context As String, ByVal security As String)
load(appset, app, userName, context, security)
End Sub
Private Function load(ByVal appsetID As String, ByVal app As String, ByVal userName As String, ByVal context As String, ByVal security As String) As Appset
...
End Function
End Class
이 코드는 클래스 이름으로도 대충 짐작이 가듯이 전체 프로그램의 공용 Meta 데이터들을 저장해 놓는 모듈이다. 이런 메타 데이터들은 많은 모듈에서 사용하면서도 프로그램이 구동 중일 때는 거의 바뀌지 않는다는 속성이 있다. 그래서 이런 메타데이터는 메모리에 하나 올려놓고, 그것을 모두 사용하면 가장 좋을 것이다. 매번 읽어오지도 않고, 각 모듈에서 각각 호출하지도 않게 하는 최선의 방법일테니까 말이다.
싱글턴 패턴
이렇게 메모리에 딱 하나의 인스턴스를 올려놓을 필요가 있을 때 쓰는 것이 바로 "Singleton" 패턴이다. "Design Patterns"에 나오는 정의를 보자면 "ensure a class has only one instance, and provide a global point of access to it" 즉 "한 클래스가 단지 하나의 인스턴스만을 가지게 하고, 그것에 액세스할 수 있는 글로벌한 포인트를 제공하는 것"이라고 되어 있다. 아래 위키 백과 페이지를 참조하면 더 자세하게 알 수 있다.
싱글턴 패턴 - 위키 백과
싱글턴 쓰임새
싱글턴 패턴은 쓰임새가 그렇게 다양하진 않다. 주로 위의 코드와 같은 메타 데이터, 혹은 파일 로깅 등의 공용 모듈에서 사용된다. (물론 위의 조건 - 하나의 인스턴스, 글로벌한 액세스 - 을 충족시킨다면 그 쓰임새 자체는 제한이 없다) 하지만 아래 글에서 볼 수 있듯이 이 Singleton 클래스는 다른 클래스들과 단단하게 결합되는(tightly-coupled) 경향이 있고, 이는 Unit Test를 어렵게 하고 전체적으로 각 모듈의 독립성을 저해하는 요소로 작용할 수도 있다. 아래와 같은 글들을 참고할 만 하다. (물론 주의깊게 읽어야 할 것이다. 단지 주장일 뿐이니)
IBM Developerworks: Use Your Singleton Wisely
PrestonLee.com: Singletons causes cancer
권장하는 닷넷 코드
MSDN: Exploring the Singleton Design Pattern
Implementing the Singleton Pattern in C#
MSDN의 Article도 괜찮긴 하지만, 2번째 글은 그야말로 총정리다. C#에서 가능한 모든 경우의 Singleton 구현에 대해서 모두 그 장단점을 서술해놓고 있다. 2번째 글을 보면 이 글의 처음에 나온 코드는 (MSDN 글을 봐도 그렇다) 그다지 좋지 못한 예라는 것을 알 수 있다..^^ 그래서 나도 현재 코드를 바꾸고 있는 중이다. 2번째 글의 네번째 버전으로(아래와 같이) 바꿀 예정이다. MSDN Article에 있는 코드와도 거의 같다고 보면 된다.
public sealed class Singleton
{
static readonly Singleton instance=new Singleton();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Singleton()
{
}
Singleton()
{
}
public static Singleton Instance
{
get
{
return instance;
}
}
}
'C# & VB.NET' 카테고리의 다른 글
[Tip]VB.NET, C# Escape 문자 (0) | 2007.10.17 |
---|---|
[Tip]현재 메소드의 호출자 정보를 알고 싶을 때... (4) | 2007.02.26 |
[HowTo]using Blogger ATOM API in C# Part I - 블로그 리스트 가져오기 (2) | 2006.09.30 |
[Tip]String 체크(C#) (0) | 2006.09.09 |
[Article]LogonUser API에서 LogonType 파라미터 (0) | 2006.07.15 |