記事ディレクトリ
I.はじめに
以前、シングルトン - C# でのシングルトン パターンの実装に関する記事を書きましたが、シングルトンとは何か、および C# での一般的なコード実装について説明しましたが、その内容は理論的なものであり、実用的ではありませんでした。
最近、WPF を使用してホスト コンピューターを作成していましたが、実際の開発でシングルトンを使用するときは、その基礎となる実装を気にしておらず、次のようなシングルトン クラス コードはめったに見られないことがわかりました。
using System;
public sealed class Singleton
{
private static volatile Singleton instance;
private static object syncRoot = new Object();
private Singleton() {
}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
代わりに、多くの場合、サービス コンテナー (ServiceProvider) を作成し、シングルトンを実装するクラスをシングルトン モードで追加し、プログラム コード全体がアクセスできるようにサービス コンテナーをパブリック (通常は App クラス内) にします。シングルトンを使用したいときは、コンテナーから取り出すだけです。
public IServiceProvider Services {
get; }
private static IServiceProvider ConfigureServices()
{
var services = new ServiceCollection();
services.AddSingleton<Class>();
...
return services.BuildServiceProvider();
}
このコンテナメソッドをこれまで使用したことがない場合は、面倒に感じるかもしれませんが、一度このメソッドを受け入れると、それがルーチンになることがわかります。ほとんどすべてのアプリケーションでこれを行うことができます (サービス コンテナーに対するこのアプローチ自体がデザイン パターン IOC です)。
これらの内容はこの記事で説明するものではありません。この記事では主に、ホスト コンピューター プログラムでのシングルトンのアプリケーションと、シナリオでのシングルトンの使用方法について説明したいと思います。
2. PC 単一ケースの適用シナリオ
2.1 ホストコンピュータ
まずホスト コンピュータについて説明します。
ホスト コンピュータは通常、それほど大きなプログラムではなく、主に次の用途に使用されます。
- ユーザーフレンドリーなインターフェイスを提供します。
- 下位のコンピューターと通信して収集されたデータを処理し、インターフェイスに表示します。
- レポート、クエリ、統計分析のために一部のデータをデータベースに保存します。
- 上位システム (MES、ERP など) と接続します。
- また、制作を支援するために、いくつかの専門技術 (視覚、文書処理など) と組み合わせる場合もあります。
特殊な機器向けのこのような小さなプログラムには、幅広いテクノロジーが含まれます。
2.2 シングルトンとそのアプリケーション
シングルトンの目的は、プログラム内でクラスのインスタンスが 1 つだけであることを保証し、それにアクセスするためのグローバル アクセス ポイントを提供することです。
明らかに、シングルトンの設計により、クラスはインスタンスを 1 つだけ持つことができ、インスタンスの制御を容易にしてシステム リソースを節約するために、外部からのアクセスが容易になる必要があります。
したがって、その適用シナリオは通常次のとおりです。
- インスタンス化が頻繁に行われ (つまり、新規が頻繁に作成され)、その後破棄されるケースがあります。
- オブジェクトの作成に時間がかかりすぎるか、リソースを大量に消費します。
- データベース接続プールやファイルなどの IO リソースに頻繁にアクセスするオブジェクト。
多くの人が初めてシングルトンを使用するのは、パフォーマンスの問題ではなく、C 言語のグローバル変数に似たものが必要で、別のページのコードからクラスのインスタンスにアクセスできることを望んでいるからだと思います。これは実際には、シングルトンで言及されているグローバル アクセス ポイントを提供する機能です。
ここでは、誰もがよく知っているアプリケーション、Windows のタスク マネージャーを紹介します。ctrl+shift+escで開きますが、何度押してもタスクマネージャーは1つしか表示されません。つまり、Windows システムではタスク マネージャーが唯一のものです。
では、なぜこのように設計されているのでしょうか?このように設計されていなかったらどうなるでしょうか?
- 複数のタスク マネージャー ウィンドウがポップアップし、これらのウィンドウに表示される内容がまったく同じである場合、開かれているオブジェクトはすべて重複するため、システム リソースの無駄が発生し、メモリの損失が発生します。実際の使用では、同じコンテンツを表示する複数のウィンドウは必要ありません。
- 複数のタスク マネージャー ウィンドウが矛盾した内容で表示される場合は、さらに状況が悪くなります。これは、ある瞬間におけるアプリケーションの使用状況、プロセス、サービス、その他の情報には複数の状態があり、どれが本当なのか?ということを意味します。明らかに、これはさらに望ましくないことです。
システム内にタスク マネージャーが 1 つだけ存在することが非常に重要であることがわかります。
2.3 ホストコンピュータでのアプリケーション
ホストコンピュータの開発でも、同様の状況に遭遇することがよくあります。一般的な例をいくつか示します。
2.3.1 ユーザーのログイン情報
ホスト コンピューターには許可機能が必要な場合があり、一部のページ機能は動作するために特定の許可を必要とします。
つまり、異なるページで取得されたユーザー情報は一貫しています。この要件を達成するには、ユーザー情報がグローバルに一意である必要があります。多くの場合、ユーザーがログインすると、さまざまな権限を含むユーザー情報がシングルトンにロードされます。
2.3.2 設定ファイル
ホスト コンピュータ プログラムには、多くの場合、機器やユーザーの習慣に関連するパラメータ設定ファイルなど、いくつかのパラメータ設定ファイルが必要です。シングルトンを使用しない場合は、毎回新しいオブジェクトを作成して構成ファイルを再読み込みする必要があり、パフォーマンスに大きな影響を与えます。シングルトンを使用する場合は、最初に 1 回読み取るだけで済みます。
2.3.3 データ接続プール
なぜプールするのでしょうか?
新しい接続の作成には時間がかかるため、新しいタスクが来るたびに新しい接続が作成されると、パフォーマンスに重大な影響を与えます。したがって、一般的なアプローチは、アプリケーション内で接続プールを維持し、タスクが到着したときにアイドル状態の接続があればそれを直接使用できるようにして、初期化のコストを排除することです。
知らせ:
ここで言うシングルトンとは、プール用のシングルトンを作成することです。、単一のデータベース接続に対してシングルトンを作成する代わりに。
データベース接続オブジェクトをシングルトン オブジェクトに封印するのは間違いです。単一のデータベース接続に対してシングルトンを作成すると、複数の関係者が接続を要求したときに、使用できるデータベース接続は 1 つだけになります。
2.4 適用シナリオについての考え方
上記の一般的な用途に加えて、ページを切り替えるときに状態を保持する必要があるためにシングルトンを使用することも試みました。
具体的なシナリオは次のとおりです。MVVM モードのホスト コンピュータに複数のページがあります。ページを切り替えた後、元のページ (ページはビューであり、ビューとみなすことができます) に戻ると、表示される内容は以前と同じになります。ページのコンテンツは、ViewModel のプロパティ、コマンドなどとして理解できます。
この要件を満たすために、シングルトンはさまざまな方法で使用できます。
- ViewModel 内のいくつかの主要なオブジェクト (通常は ViewModel 内の集約されたモデル) をシングルトン化します。
- ViewModel をシングルトンにして、プログラム内に ViewModel が 1 つだけになるようにします。
- ビュー全体をシングルトン化します。
方法1
ViewModel 内のキー オブジェクトがシングルトン化されている場合、元のページに戻るときに ViewModel が再作成され、これらのシングルトン オブジェクトがそこに読み込まれます。
方法 2
ViewModel 全体をシングルトン化する場合は、ビューの DataContext をシングルトン ViewModel にバインドするだけで済みます。
方法3
ビュー全体がシングルトン化されている場合は、ターゲットのシングルトン ビューに移動してページを切り替えるだけで済みます。
そこで問題は、どちらの方法が良いのかということです。
この種の質問に対する答えは明らかにありません。それはより具体的なシナリオによって異なります。
シングルトンを使用せずにホームページ クラスに複数のサブページを集約し、クリックするだけでサブページに移動することもできます。
シングルトンを使用する場合に戻ります。
ビューモデルに多数のモデルが集約されており、それらのモデルが他のページで使用される可能性がある場合、明らかにこれらのモデルはシングルトン化する必要があります。
ビューモデルに独立したステータス項目が多数ある場合、ページのステータスのみが記録され、モデルとはほとんど関係がありません。ViewModel 全体をシングルトンにすることも合理的です。
ビュー内にキャンバスなどのリンクされたオブジェクトがあり、キャンバス上に絵を描く場合、キャンバスはビューに属します。View をシングルトンにすることも合理的です。
最終的にどの方法が使用されるかについては明確な答えはありません。現時点では、現実の状況に基づいて一見合理的と思われる方法を選択し、実践を通じてテストすることしかできません。
3. まとめ
シングルトンは非常に基本的なデザイン パターンです。プログラム内でクラスのインスタンスが 1 つだけであることを確認し、そのインスタンスへのグローバル アクセス ポイントを提供します。それでおしまい。
一般的なアプリケーション シナリオ、ユーザー ステータス、構成ファイル、データベース接続プールなど。
同じモデルを複数のページで使用する場合にも使用できます。効果が得られるのであれば、シーンによってはあまり気にする必要はありません。