こんにちは、お久しぶりです!

Ayakaです。(なんとなく英語表記にしてみた)

 

最近イベントごとが多くて東京に何回も行かせていただいてます。

(実は来週の土日にまたゲームジャムの為遠征です)

専門学校入学したときよりも東京に特別感がなく、むしろすごい馴染んでいるのはいいことだと思いたい(笑)

また、インターンシップも何社かエントリーさせていただいたので是非是非よろしくお願いします!

 

そんな忙しい中でもやっぱりブログ更新はやらないと……。

段々頻度を増やしていけれたらなぁと思ってます!

(悲しいことに、理解不十分なものが……!)

 

では、久しぶりの今日のお題は……singleton

デザインパターンですね。4人の技術者の方が考えてくれた23つある設計のうちの1つです。

使ってみるとプログラムが分かりやすく、また再利用もしやすいので非常にありがたい!

 

……理解していればの話ですがね(;´・ω・)

 

今年から始まったこの授業、現段階で「singleton」と「Factory method」、「strategy」に「state」とやってきましたが……危うい!

昨日なんとかstateの壁を越えてきました……スッキリ。

とはいえあと3つ!そのうちの1つ!ちゃんとやるぞ!!

 

では、毎度おなじみコードから……

 

class Hi_score
{
public:

  //スコア
    int hi_score;


private:
    Hi_score()
    {
        hi_score = 1000;
    }
public:

   //一つしか作らない
    static Hi_score& GetInstance()
    {
        static Hi_score* instance = new Hi_score();

        if (instance == nullptr)
        {
            instance = new Hi_score();
        }
        return *instance;
    }
  };
 

//スコアを1にする

void One()
{
    Hi_score& hiscore = Hi_score::GetInstance();
    hiscore.hi_score = 1;
}

//スコアに999足す
void Nine()
{
    Hi_score& hiscore = Hi_score::GetInstance();
    hiscore.hi_score += 999;
}


int main()
{
    Hi_score& hiscore = Hi_score::GetInstance();
    
    cout << hiscore.hi_score << endl;

    One();
    cout << hiscore.hi_score << endl;

    Nine();
    cout << hiscore.hi_score << endl;

    return 0;
}

 

なんだこの醜いコードは!!!(声大)

関数名迷ったにせよOneとNineはひどすぎませんか私……

そもそもpublicに変数がある時点で……ま、まぁテストだから!!許してください!!!

 

さて……実行結果はといいますと

 

1000

1

1000

 

となります!

……へ、何が何だか分からない?

ええ、私がです……

 

まず、疑問なのはGetInstanceの存在。

全部の関数で、普通に宣言させてくれない!(Hi_score hiscore=new Hi_score();のように)

絶対にGetInstanceを取得しなければならない点。

 

そして、関数に引数を渡していないのに、One()関数を呼び出したらスコアが1になっていること、Nine()関数を呼び出したら1に+999されていること。

今までだったら

//スコアに1を代入
int One(int score)
{
    score = 1;
    return score;
}

//スコアに+999する
int Nine(int score)
{
    score += 999;

    return score;
}

int main(void)
{
    int Score;
    Score = 1000;
    cout << Score << endl;
    Score = One(Score);
    cout << Score << endl;
    Score = Nine(Score);
    cout << Score << endl;

    return 0;
}

こうしなければ同じような結果にはならなかったのに……

 

……さて、ここでsingletonとはどういうデザインパターンなのか、という事が分かってきたかと。

「single」っていうのは、「単」、「ただ1つ」という意味ですよね。(Google翻訳先生参照)

そして今回のこの結果……。

そう、スコアは多重に存在していない

1つのスコアを書き換えたり(One()で1を代入)、1つのスコアに対して計算したり(Nine()で+999)していたわけです。

つまり、プログラム上1つしか要らない、必要のないものに対してこのデザインパターンが使える!!

 

さぁ、問題のクラスを見てみると

class Hi_score
{
public:

  //スコア
    int hi_score;


private:
    Hi_score()
    {
        hi_score = 1000;
    }
public:

   //一つしか作らない
    static Hi_score& GetInstance()
    {
        static Hi_score* instance = new Hi_score();

        if (instance == nullptr)
        {
            instance = new Hi_score();
        }
        return *instance;
    }
  };

よくよく見ると、privateにコンストラクタがあるんです!

問題のGetInstance()を呼び出さないといけない理由は、コンストラクタに直接アクセスできないから……

えーそんな馬鹿な……

GetInstanceを呼び出すと、静的変数であるinstanceにnewされます。

 

では、順々に関数を呼び出してみます。

int main()
{
    Hi_score& hiscore = Hi_score::GetInstance();
    
    cout << hiscore.hi_score << endl;

    One();
    cout << hiscore.hi_score << endl;

    Nine();
    cout << hiscore.hi_score << endl;

    return 0;
}

 

まず、main関数内の

Hi_score& hiscore = Hi_score::GetInstance();

で、始めの初期値1000の入ったHi_scoreが生成されます。

 

次のOne()関数にて

//スコアを1にする

void One()
{
    Hi_score& hiscore = Hi_score::GetInstance();
    hiscore.hi_score = 1;
}

ここでのHi_score& hiscore = Hi_score::GetInstance();

で、さっきmain関数で生成した初期値1000の入ったHi_scoreが取得されます!

その次の文hiscore.hi_score = 1;であっさりとHi_score内を1にしちゃいますが……

 

そして最後のNine()関数で

//スコアに999足す
void Nine()
{
    Hi_score& hiscore = Hi_score::GetInstance();
    hiscore.hi_score += 999;
}
 

お察しの通り、ここのHi_score& hiscore = Hi_score::GetInstance();

でも、さっき1を代入したHi_scoreさんが取得されます。

そこに+999して,めでたく1000に……!

 

singletonのポイントは

*コンストラクタはprivate(単一しか存在させないため、外部からの生成を防ぐ)

*その代わりにGetInstance()で取得。

*とにもかくにも単一!

 

ですね!

 

……どうしよう、うまくまとまっている気がしない……困った。

とはいえ、今からこのsingletonくんを実装せねば。なのでゆったりとクラシック聴きながらやってきますとも!