至る所にたくさんのシングルトンがあるレガシーコードがあります(C#で記述)。
シングルトンは、パターンのかなり「古典的な」実装です。
public class SomeSingleton
{
private static SomeSingleton instance;
private SomeSingleton()
{
}
public static SomeSingleton Instance
{
get
{
if (instance == null)
{
instance = new SomeSingleton();
}
return instance;
}
}
}
スレッドの安全性は問題ではないため、ロックは使用されないことに注意してください。
コードをよりテストしやすくするために、あまり多くの変更を加えずに、このコードを変更して、別のクラス(ファクトリーまたは同様のパターン)でのシングルトンインスタンスの作成を委任したいと思います。
これは、テスト目的の「テスト」インスタンス、または現在使用されている実際のバージョンの作成に役立ちます。
これは一般的な方法ですか?このようなパターンへの参照が使用されていませんでした。
コメントで、ゲーム開発にUnityとMonoを使用していると言います。それはMicrosoft UnityではなくUnity3Dを意味していると思います。そのため、フォローしているシングルトンパターンを破棄し、代わりに依存関係注入を使用することをお勧めします。 unity3dフレームワークでZenjectを使用できると思います。
シングルトンクラスは、次のようなインターフェイスのインスタンスになるように変更されます。
public class IImportantInterface
{
DoSomethingImportant();
}
public class MySingletonImplementation: IImportantInterface
{
public void DoSomethingImportant()
{
Console.WriteLine("This is Important!");
}
}
public class DoImportantStuff
{
private readonly IImportantInterface _ImportantInterface;
public DoImportantStuff(IImportantInterface importantInterface )
{
_importantInterface = importantInterface;
}
public void DoSomething()
{
_importantInterface.DoSomethingImportant();
}
}
次に、起動ロジックでシングルトンインスタンスをZenjectに登録できます。
Container.Bind<IImportantInterface>().ToSingle<MySingletonImplementation>();
この概念についての良いブログ投稿はここにあります: http://www.unityninjas.com/code-architecture/dependency-injection/
これには、制御の反転が必要です。まず、SomeSingletonにインターフェイスを追加して、ISomeSingletonと言います。次に、ISomeSingletonのすべてのコンシューマーは、ISomeSingletonのコンストラクターパラメーターを取得します。
例:
public class Consumer1 {
readonly ISomeSingleton _mySingleton;
public Consumer1(ISomeSingleton mySingleton) {_mySingleton = mySingleton;}
}
public interface ISomeSingleton{//All your methods you ned.}
public class SomeSingleton : ISomeSingleton
{
private static SomeSingleton instance;
public SomeSingleton() // constructor is now public
{
}
public static SomeSingleton Instance // todo remove this when all consumers follow inversino of control pattern.
{
get
{
if (instance == null)
{
instance = new SomeSingleton();
}
return instance;
}
}
}
消費者がSomeSingletonを直接呼び出さない場合は、それを削除できます。これにより、自分のペースで変更を加えることができます。
これで、SomeSingletonをインスタンス化する方法を理解する必要があります。これを手動で行うか、IOCコンテナを使い始めることができます。
テストでは、ISomeSingletonの異なる実装を作成できます。