この記事は主に、「シングルトンクラスと静的クラスの主な違いは何か、どちらを使用するか、もう一方はいつ使用するか」という質問を聞いたときにインタビューで迷子になった開発者に役立ちます。 そして、「パターン」という言葉で落胆したり、自分自身の表現をやめるように要求したりする開発者にとっては確かに役立つでしょう。
静的クラスとは何ですか?
最初に、静的クラスとは何か、なぜ静的クラスが必要なのかを思い出しましょう。 CLI準拠の言語では、グローバル変数をカプセル化するための次のパラダイムが使用されます。グローバル変数
はありません 。 静的メンバーを含むすべてのメンバーはクラス内でのみ宣言でき、クラス自体は任意の名前空間でグループ化できます(
ただし、グループ化はでき
ません )。 また、プライベートコンストラクターを使用して静的クラスの動作を模倣する必要がある場合、プラットフォームレベルでの静的クラスのサポートが.NET Framework 2.0に追加されました。 静的クラスと通常の非静的クラスの主な違いは、
new演算子を使用してこのクラスをインスタンス化できないことです。 静的クラスは本質的に一種の名前空間です-後者とは異なり、型ではなく静的変数とメソッドを保持するように設計されています。
シングルトンとは何ですか?
Gang of Four (GoF)によって最初に記述された
生成パターンの1
つ 。 クラスが
1つのインスタンスのみを持ち、それに
グローバルアクセスポイントを提供するようにします。 ここでは、このパターン、その目的、およびそれが解決するタスクを詳細に検討しません。ネットワークには、このパターンに関する多くの詳細情報があります(たとえば、
hereおよび
here )。 シングルトーンはスレッドセーフであり、初期化が単純で遅延しているため、スレッドセーフではないことに注意してください。
そして違いがない場合-なぜもっと生産するのですか?
では、これら2つのエンティティの違いは何ですか?また、いつ使用する必要がありますか? これを次の表で説明するのが最善だと思います。
| シングルトン
| 静的クラス
|
---|
アクセスポイントの数
| 1つだけのアクセスポイント- インスタンスの静的フィールド
| N(パブリッククラスメンバーとメソッドの数に依存)
|
クラス継承
| おそらくではありますが、常にではありません(以下で詳しく説明します)
| 不可能-静的クラスのオブジェクトのインスタンスを作成できないため、静的クラスをインスタンス化できません
|
インターフェイスの継承
| おそらく制限なし
| クラスの継承が不可能であるのと同じ理由で不可能
|
パラメーターとして渡す機能
| おそらくシングルトンが実際のオブジェクトを提供するため
| 行方不明です
|
オブジェクト寿命監視
| おそらく-たとえば、 初期化の遅延 (またはオンデマンドの作成 )
| クラスの継承が不可能であるのと同じ理由で不可能
|
抽象ファクトリーを使用してクラスをインスタンス化する
| たぶん
| インスタンスを作成する可能性がないため不可能
|
連載
| たぶん
| インスタンスが不足しているため、該当しません。
|
上記の基準をより詳細に検討してください。
アクセスポイントの数
もちろん、
外部アクセスポイント、つまり、クラスとそのクライアントの対話のためのパブリックコントラクトを意味します。 コードを使用してこれを説明する方が便利です。
「標準」実装のシングルトン:
public class Session { private static Session _instance;
静的クラス:
public static class Session {
クラス継承
静的クラスの継承は簡単です-言語レベルではサポートされていません。 シングルトンでは、物事はもう少し複雑です。 使いやすさのために、多くの開発者はほとんどの場合、次のパターン実装を使用します。
public class Singleton<T> where T : class { private static T _instance; protected Singleton() { } private static T CreateInstance() { ConstructorInfo cInfo = typeof(T).GetConstructor( BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[0], new ParameterModifier[0]); return (T)cInfo.Invoke(null); } public static T Instance { get { if (_instance == null) { _instance = CreateInstance(); } return _instance; } } } public class Session : Singleton<Session> { public IUser GetUser() {
また、C#およびCLI互換言語では多重継承が禁止されているため、他の
有用なクラスからSessionクラスを継承することはできません。 解決策は、アクセスインスタンスインスタンスをシングルトンにデラグすることです。
public class Session : CoreObject { private Session() { } public static Session Instance { get { return Singleton<Session>.Instance; } } }
インターフェースの継承
インターフェイスを使用すると、柔軟性が高まり、再利用可能なコードの数が増え、テスト容易性が向上し、最も重要なことには、オブジェクトの
強力な接続を回避できます。 静的クラスは原則として継承をサポートしていません。 一方、シングルトンは通常のクラスであるため、インターフェイスの継承を完全にサポートしています。 ただし、この機会を利用する価値があるのは、混合シナリオでシングルトンインスタンスを入力パラメーターとして送信する場合、または海外にブロードキャストする場合のみです。 混合シナリオの例:
パラメーターとして渡す機能
静的クラスの場合、これはサポートされていません-型のみを渡すことができますが、ほとんどの場合、リフレクションメカニズムが使用される場合を除き、それは役に立たない。 シングルトンは基本的にオブジェクトの通常のインスタンスです。
オブジェクト寿命監視
静的クラスのライフタイムは、ドメインのライフタイムによって制限されます。このドメインを手動で作成した場合、すべての静的タイプのライフタイムを間接的に制御します。 希望に応じてシングルトンの存続期間を制御できます。 顕著な例は、遅延初期化です。
public class Singleton<T> where T : class {
また、シングルトンインスタンスの削除操作を追加することもできます。
public class Singleton<T> where T : class {
この操作は非常に安全ではありません。シングルトンは何らかの状態を保存できるため、再作成するとクライアントに望ましくない結果をもたらす可能性があります。 それでもこのようなメソッドの必要性が生じた場合(設計エラーを示している可能性が高い)、その使用による可能性のある悪を最小限に抑えるようにする必要があります。たとえば、特定の条件下でメソッドを閉じて内部のInstanceプロパティを呼び出します。
public class Singleton<T> where T : class {
抽象ファクトリーを使用してクラスをインスタンス化する
静的クラスのインスタンスを作成できないため、静的クラスはこの機能をサポートしません。 シングルトンの場合、すべてがシンプルに見えます。
public interface IAbstractFactory { T Create<T>(); bool IsSupported<T>(); } public class Singleton<T> where T : class { private static T _instance; private static IAbstractFactory _factory; protected Singleton(IAbstractFactory factory) { _factory = factory; } public static T Instance { get { if (_instance == null) { _instance = _factory.Create<T>(); } return _instance; } } }
確かに、シングルトン集約のバリアントでは、あまり美しくなく、少し面倒な解決策を適用する必要があります。
public class Session : CoreObject, ISession { private class SessionSingleton : Singleton<Session> { protected SessionSingleton() : base(new ConcreteFactory2()) { } } private Session() : base(new CoreContext()) { } public static Session Instance { get { return SessionSingleton.Instance; } }
連載
シリアル化は、クラスインスタンスにのみ適用されます。 静的クラスはインスタンスを持つことができないため、この場合、シリアル化するものはありません。
それでは、SingletonまたはStaticクラスを使用するのは何ですか?
いずれにしても、ソリューションの選択は、開発者と彼が解決しているタスクの詳細に依存します。 しかし、いずれにしても、次の結論が導き出されます。
シングルトンの使用は、次の場合に正当化されます。
- クラスまたはインターフェースを継承するか、オブジェクトの構築をファクトリーに委任する必要があります
- クラスインスタンスの使用が必要
- オブジェクトのライフタイムを制御する必要があります(ただし、これはシングルトンにとって非常にまれなタスクです)
- オブジェクトをシリアル化する必要があります(このようなタスクは仮説的には可能ですが、ユースケースを想像するのは困難です)
シングルトン用にリストされているスクリプトを実装する必要がない場合
は、静的クラスを使用することをお勧めします。 静的クラスの主な目的は、論理的に類似したメソッド、定数、フィールド、プロパティのグループ化にあります。 例:
System.Math 、
System.BitConverter 、
System.Buffer 、
System.Convertなど。