C++などのオブジェクト指向言語では,デバイスや周辺機能をクラスとして定義して扱うことになります.ただし,通常のクラスの場合,メモリが許す限りいくつものオブジェクトを作成できてしまいます.実際にはデバイスが1個しかない場合に,プログラム上では複数のデバイスが存在してしまう状況はおかしなことですよね?.そこで登場するのがシングルトンです.シングルトンとは,GoFの定義した23種類のデザインパターンのうちの一つです.GoFとは,Gang of Four(4人組)の略称であり,その4人とは,いずれもソフトウェア科学者のErich Gamma, Rechard Helm, Ralph E. Johnson, John Matthew Vlissidesです.この4人が著した書籍の中で定義した23種類のプログラムの「型」をデザインパターンといいます.ただし,23種類以外のパターンも存在します.
シングルトンでは生成されるオブジェクトを1個に限定させることができます.ここではLEDを例にとって話をします.メインマイコンボードにはLED7が存在し,Led7クラスを作るとします.このLed7クラスをインスタンス化するとき1個しかオブジェクトを作成できないようにクラスを設計します.まず,要点を箇条書きで下に示します.
- コンストラクタ(C++の場合,コピーコンストラクタと代入演算子を含む)をプライベートにする
- そのクラスをインスタンス化した,プライベートかつスタティックであるフィールドを持つ
- スタティックかつパブリックなgetInstanceメソッドにより,上記フィールドをクラス外部へ提供する
クラス図で表すと下のようになります.
このように,コンストラクタ,コピーコンストラクタおよび代入演算子すべてをプライベートにしてありますので,Led7クラスの外からはLed7型のオブジェクトを作ることができません.その代わり,getInstanceメソッドによりオブジェクトを得られるようになっており,このメソッドから返されるオブジェクトはスタティックなフィールドled7を返すようになっています.このため,結果として常にled7しかオブジェクトが存在しないことになります.下にプログラム例を示します.まずはヘッダファイルです.プライベートになっているメソッドに注目してください.
class Led7 { private: /** * Singleton用インスタンス */ static Led7* _singleton; private: /** * コンストラクタ */ Led7(); /** * コピーコンストラクタ * @param[in] src コピー元 */ Led7(const Led7& src); /** * 代入演算子 * @param[in] src コピー元 */ Led7& operator=(const Led7& src); /** * 初期化する */ void _initialize(); public: /** * デストラクタ */ virtual ~Led7(); /** * インスタンスを取得する<br> * Singletonのための関数 * @return Singleton化されたインスタンス */ static Led7* getInstance(); /** * 点灯させる */ void turnOn(); /** * 消灯させる */ void turnOff(); };
次にソースです.
#include #include "iodefine.h" #include "Led7.hpp" Led7* Led7::_singleton = NULL; Led7::Led7(){ /* なにもしない */ } Led7::Led7(const Led7& src){ /* シングルトンをコピーしておく */ _singleton = src._singleton; } Led7& Led7::operator=(const Led7& src){ /* シングルトンをコピーしておく */ _singleton = src._singleton; return *this; } void Led7::_initialize(){ /* LED7が接続されているポートEビット4を出力端子にする */ PORTE.DDR.BIT.B4 = 1; /* ポートEビット4から1を出力(=消灯)させる */ PORTE.DR.BIT.B4 = 1; } Led7::~Led7(){ /* オブジェクトを消す */ delete _singleton; } Led7* Led7::getInstance(){ /* 初めてLEDを使うとき */ if(_singleton == NULL) { /* メモリの確保 */ _singleton = new Led7(); /* 初期化 */ _singleton->_initialize(); } return _singleton; } void Led7::turnOn(){ /* 点灯させるため,Lowを出力する */ PORTE.DR.BIT.B4 = 0; } void Led7::turnOff(){ /* 消灯させるため,Highを出力する */ PORTE.DR.BIT.B4 = 1; }
さらに,Led7の使い方を下に示します.3行目のコメントアウトしてあるプログラムは,コンストラクタがプライベートになっているため,コンパイルエラーとなります.オブジェクトを得るには,6行目のようにgetInstanceメソッドを使います.そして,得られたオブジェクトを使ってturnOnおよびturnOffメソッドを呼び出します.
void main(){ /* 下のようにしてもコンパイルエラーとなる */ // Led7 *led7 = new Led7(); /* インスタンスを得る */ Led7 *led7 = Led7::getInstance(); /* 点灯する */ led7->turnOn(); /* 消灯する */ led7->turnOff(); }
以上のように,シングルトンにすることで1個のオブジェクトのみに限定することができます.