改訂版書きました。
[改訂版]継承可能なSingleton基底クラス(VB.Net)
Singletonなクラスをある程度の個数作らなければいけなくなり、スニペットはあるもののなんとか継承を使用して解決できないか調査した。
参考にしたサイト
Singletonのサブクラス化
デザインパターン第14回「Singletonパターン」その2
基底クラス
AbstractSingletonClass.vb
''' <summary>
''' シングルトン基底クラス
''' </summary>
''' <remarks></remarks>
Public MustInherit Class AbstractSingletonClass
''' <summary>
''' シングルトンインスタンスリスト
''' </summary>
''' <remarks></remarks>
Private Shared _SingletonInstanceDictionary As New Dictionary(Of Type, AbstractSingletonClass)
''' <summary>
''' インスタンス生成排他ロックオブジェクト
''' </summary>
''' <remarks></remarks>
Private Shared ReadOnly _SyncLockCreateInstance As New Object
''' <summary>
''' コンストラクタ(Protected)
''' </summary>
''' <remarks></remarks>
Protected Sub New()
'唯一のインスタンスを保証する
If _SingletonInstanceDictionary.ContainsKey(Me.GetType()) Then
Throw New InvalidOperationException("インスタンスは既に生成されています。")
End If
'追加する
_SingletonInstanceDictionary.Add(Me.GetType(), Me)
End Sub
''' <summary>
''' インスタンス取得
''' </summary>
''' <typeparam name="T"></typeparam>
''' <returns></returns>
''' <remarks></remarks>
Public Shared Function GetInstance(Of T As AbstractSingletonClass)() As T
SyncLock _SyncLockCreateInstance
'インスタンス生成済みかチェックする
If _SingletonInstanceDictionary.ContainsKey(GetType(T)) = False Then
'無ければ生成する
_SingletonInstanceDictionary(GetType(T)) = CType(System.Activator.CreateInstance(GetType(T), True), T)
End If
'返す
Return CType(_SingletonInstanceDictionary(GetType(T)), T)
End SyncLock
End Function
End Class
派生クラス
SingletonA.vb
''' <summary>
''' 派生クラスA
''' </summary>
''' <remarks></remarks>
Public Class SingletonA
Inherits AbstractSingletonClass
''' <summary>
''' コンストラクタ(Protected)
''' </summary>
''' <remarks></remarks>
Protected Sub New()
End Sub
End Class
使い方
Dim S = SingletonA.GetInstance(of SingletonA)()
今回勉強になったポイント
1.インスタンスを生成するActivator.CreateInstanceメソッドは、Publicなコンストラクタのみを実行するものだと思っていたが、第2引数次第でProtected、Privateでも生成してくれることを知った。
2.Sharedなメンバは「基底クラス.Sharedメンバ」とアクセスしなければいけないと思い込んでいたため、派生クラス内に基底クラス名が出現するが嫌で敬遠していた。だが「派生クラス.Sharedメンバ」でもOKなことを知った。
残る問題
こんな感じで使う時に型推論が効けば最高。
Dim S = SingletonA.GetInstance()
解決方法をご存知の方、コメントください。