Singletonパターンでモードレスダイアログを作成する

モードレスダイアログを作成する方法はいくつかあるが、ダイアログクラスをSingletonパターンを使った定義にすることでモードレスダイアログを作成することもできる。この場合、クラス自身が二重起動の防止などの処置をしてくれるため使いやすい。


Singletonパターンとは?
Singletonパターンはデザインパターンの1つである。デザインパターンとは、オブジェクト指向ソフトウェアの設計に際してよく使用される思考方法などをパターンとしてまとめたものである。
このうちSingletonパターンは生成に関するパターンの1つとして分類され、あるクラスに対してインスタンスが1つしかないことを保証し、それにアクセスするためのグローバルな方法を提供する、というものである。
// Singletonクラスの定義
class Singleton{
public:
    static Singleton* Instance();	// インスタンスの生成を行う静的メンバ関数

protected:
    singleton();			// デフォルトコンストラクタはprotectedにする

private:
    static Singleton* _instance;	// 生成されたインスタンスへのポインタを持つ静的メンバ変数
};

// 静的メンバ変数の初期化
Singleton* Singleton::_instance = NULL;

// 静的メンバ関数の実装
Singleton* Singleton::Instance(){
    if(_instance == NULL){
        _instance = new Singleton;
    }
    return _instance;
}
上記はSingletonクラスの簡単な定義である。デフォルトコンストラクタがprotected指定されているので、通常の方法ではインスタンスを生成することはできない。静的メンバ関数であるSingleton::Instance()を呼び出すことで生成可能である。
    Singleton single;                   // エラー
    Singleton* pSingle = new Singleton; // エラー
    Singleton::Instance();              // 正しい
ここでSingleton::Instance()の実装に注目してほしい。この中ではまず静的メンバ変数_instanceがNULLかどうか判定している。この変数は生成されたインスタンスへのポインタを持つ。つまり、この変数がNULLでないときはすでにインスタンスが生成されているので、if文の中にある処理が呼ばれない。すなわちデフォルトコンストラクタは呼ばれることはなく、これ以上インスタンスが生成されることはないわけである。

モードレスダイアログクラスの実装
上記のパターンを利用して、モードレスダイアログクラスを定義する。
// クラスの定義 ---------------------------
class CSingletonDialog : public CDialog
{
// コンストラクション
public:
    static CSingletonDialog* Instance();        // インスタンスの生成を行う静的メンバ関数

protected:
    CSingletonDialog(CWnd* pParent = NULL);     // デフォルトコンストラクタはprotectedにする!
……

private:
    static CSingletonDialog* m_Instance;        // 生成されたインスタンスへのポインタを持つ静的メンバ変数
};

// クラスの実装 ---------------------------
// 静的メンバ変数の初期化
CSingletonDialog* CSingletonDialog::m_Instance = NULL;

// 静的メンバ関数の実装
CSingletonDialog* CSingletonDialog::Instance()
{
	if( m_Instance == NULL ) {
		m_Instance = new CSingletonDialog;
	}
	return m_Instance;
}

// デフォルトコンストラクタの実装
CSingletonDialog::CSingletonDialog(CWnd* pParent /*=NULL*/)
	: CDialog(CSingletonDialog::IDD, pParent)
{
	//{{AFX_DATA_INIT(CSingletonDialog)
		// メモ - ClassWizard はこの位置にマッピング用のマクロを追加または削除します。
	//}}AFX_DATA_INIT
	Create(IDD_DIALOG_MODERESS);
}

// OnCancel関数
void CSingletonDialog::OnCancel() 
{
	// TODO: この位置に特別な後処理を追加してください。
	CDialog::OnCancel();

	delete m_Instance;
	m_Instance = NULL;
}
先に記したSingletonパターンの定義とほとんど変わらない。追加されたのはデフォルトコンストラクタ内でCreate関数を呼び出してモードレスダイアログを生成する処理と、OnCancel関数内でダイアログの破棄を行う処理である。もちろん、OKボタンでダイアログを閉じる場合はOnOK関数にも同じ処理を施さなければならない。
※ モードレスダイアログに使用するダイアログリソースは、ClassWizardのプロパティで必ず「可視」をチェックしておくこと。

目次へ