シングルトンパターン
シングルトン パターンでは、クラスにインスタンスが 1 つだけ存在し、グローバル アクセス ポイントが提供されることが保証されます。これにより、システム内に複数の同一オブジェクトが出現することを回避できるため、システムのパフォーマンスと保守性が向上します。
シングルトン モードの実装には、Hungry Man と Lazy Man が含まれます。以下では、これら 2 つのメソッドを C++ で記述する方法を紹介します。
ルーティーン
お腹を空かせた男
ハングリー モードでは、プログラムが開始される前にインスタンスが作成されます。
以下はグローバルカウンターの例です。
カウンタ.h
class Counter
{
public:
static void plus(int number);
static void print();
private: //method
Counter();
private: //member
static Counter counter;
int value {
0 };
};
カウンタ.cpp
#include "counter.h"
#include <iostream>
using namespace std;
Counter::Counter()
{
cout << "init Counter" << endl;
}
Counter *Counter::instance()
{
return &counter;
}
void Counter::plus(int number)
{
counter.value += number;
}
void Counter::print()
{
cout << counter.value << endl;
}
移行
#include "counter.h"
int main()
{
cout << "program run" << endl;
Counter::plus(5);
Counter::print();
return 0;
}
怠け者
Lazy モードは、インスタンスが初めて取得されるときに呼び出されます。
先ほどと同じ例です。
カウンタ.h
class Counter
{
public:
static Counter* instance();
void plus(int number);
void print();
private: //method
Counter();
private: //member
int value{
0 };
};
カウンタ.cpp
#include "counter.h"
#include <iostream>
using namespace std;
Counter* Counter::instance()
{
static Counter* counter = NULL;
if (counter == NULL)
counter = new Counter;
return counter;
}
Counter::Counter()
{
cout << "init Counter" << endl;
}
void Counter::plus(int number)
{
value += number;
}
void Counter::print()
{
cout << value << endl;
}
移行
#include "counter.h"
int main()
{
cout << "program run" << endl;
Counter::instance()->plus(5);
Counter::instance()->print();
return 0;
}
比較した
上記の例から、飢えた人モードと怠け者モードの間には次のような違いがあることがわかります。
関数呼び出し
Counter::plus(5);
Counter::print();
Counter::instance()->plus(5);
Counter::instance()->print();
怠け者はメソッドを呼び出すために関数 instance() をインスタンス化する必要がありますが、飢えた人はその必要がありません。明らかに、クライアントにとっては飢えた人モードの方が使いやすく、効率的です。
スレッドの安全性
怠け者はインスタンスを取得した場合にのみインスタンスをインスタンス化しますが、メインスレッドと子スレッドが同時にinstance()を呼び出すというスレッドの安全性の問題があります。これは明らかに安全ではないため、このシングルトンが複数のスレッドで共有されている場合は、ロックする必要があります。
怠け者のスレッド セーフティの問題を解決するには、コードに次の変更を加えます (ここで使用されるロックは Qt のミューテックス ロックです)。
Counter* Counter::instance()
{
static QMutex mutex;
static Counter* counter = NULL;
if (counter == NULL) {
mutex.lock();
if (counter == NULL)
counter = new Counter;
mutex.unlock();
}
return counter;
}
最初に counter == NULL を判定してからロックするのは、毎回ロックすることによるパフォーマンスの低下を避けるためです。 コード長は増加しますが、追加された部分の実行回数は非常に少ないため、パフォーマンスへの影響は無視できます。 。
要約する
上記の比較を通じて、一般的には、Hungry Man の方が Lazy Man よりも優れていることがわかりますが、ロードする必要がある単一インスタンスが多数あり、時間がかかる場合は、Lazy Man の使用を検討できます。