Skeleton of GOF's Design Pattern


SINGLETONの骸骨

SINGLETON

プロセス内に、オブジェクトが一つしか存在しないことを保証するためのパターンです。コンストラクタを隠蔽化することによって、生成を自身の責任のもとで制御します。コンストラクタを、隠蔽することによって、クライアントは、Singleton のインスタンスを自由に作れなくなるため、インスタンスのユニーク性が保証されます。

SINGLETON は、インスタンス生成をクライアント側で制御できる(これを、遅延初期化といいます)ため、タイミングを間違えると、他のオブジェクトが、Singleton の実体がないまま、メソッドを呼び出してしまうことがあるので注意が必要です。(起動終了時に多い不具合です)

これに関連して、文献[1]では、Singleton 同士に依存関係があるような場合は、このパターンは使えないということが指摘されています。


■ 『SINGLETONの骸骨』の構造


■ 『SINGLETONの骸骨』 プログラム・コード

□ Java2版
// Copyright(C) 2000-2003 Yoshinori Oota All rights reserved.

public class SingletonSample { 
   static public void main(String[] args) { 
       Singleton theSingleton = Singleton.Instance();
       theSingleton.printState();
       theSingleton.nextState();
       theSingleton.printState();

       //ここで、インスタンスを新たに呼び出してみよう!
       //anotherSingletonのStateは初期化されてしまうのでしょうか?
       Singleton anotherSingleton = Singleton.Instance();
 
       //されてませんでしたね。インスタンスのユニーク性は、
       //保証されているようです。
       anotherSingleton.printState();
       theSingleton.printState();

       //anotherSigletonも、theSingiletonも同じ実体を操作している。
       anotherSingleton.nextState();
       anotherSingleton.printState();
       theSingleton.printState(); 
    } 
}

class Singleton { 
    private String _state = "initial state";
    private static Singleton _instance = null; 

    private Singleton() { } 
    public static Singleton Instance() { 
        if (_instance == null) { 
            _instance = new Singleton(); 
        }
        return _instance; 
    } 
    public void printState() { 
        System.out.println(_state); 
    } 
    public void nextState() { 
        if (_state.compareTo("initial state") == 0) { 
            _state = "second state"; 
        } else if (_state.compareTo("second state") == 0) { 
            _state = "third state"; 
        } else if (_state.compareTo("third state") == 0) { 
            _state = "initial state"; 
        } 
    } 
} 

○ C++版
// Copyright(C) 2003 Yoshinori Oota All rights reserved.

#include <iostream>
using namespace std;

class Singleton {
public:
    static Singleton* Instance();
    static void Destroy();
    void nextState();
    void printState() const;
private:
    Singleton();
    ~Singleton();
    static Singleton* theInstance;
    string value_;
};


Singleton* Singleton::theInstance = NULL;

Singleton::Singleton() : value_("initial state") { }
Singleton::~Singleton() { }
Singleton* Singleton::Instance() {
    if (theInstance == NULL) {
        theInstance = new Singleton();
    }
    return theInstance;
}
void Singleton::Destroy() {
   if (theInstance != NULL) {
       delete theInstance;
       theInstance = NULL;
   }
}
void Singleton::nextState() {
    if (value_ == "initial state") {
        value_ = "second state";
    } else if (value_ == "second state") {
        value_ = "third state";
    } else if (value_ == "third state") {
        value_ = "initial state";
    }
}
void Singleton::printState() const {
    cout << value_ << endl;
}


int main() {
   Singleton* theSingleton = Singleton::Instance();
   theSingleton->printState();
   theSingleton->nextState();
   theSingleton->printState();

   //ここで、インスタンスを新たに呼び出してみよう!
   //anotherSingletonのStateは初期化されてしまうのでしょうか?
   Singleton* anotherSingleton = Singleton::Instance();
 
   //されてませんでしたね。インスタンスのユニーク性は、
   //保証されているようです。
   anotherSingleton->printState();
   theSingleton->printState();

   //anotherSigletonも、theSingiletonも同じ実体を操作している。
   anotherSingleton->nextState();
   anotherSingleton->printState();
   theSingleton->printState(); 

   //デストラクタも隠蔽することにより、2重deleteを防げる
   Singleton::Destroy();
}

○ C版
/* Copyright(C) 2009 Yoshinori Oota All rights reserved. */
#include <stdio.h>
#include <stdlib.h>
/* Singleton */
struct Singleton {
    char *state_;
};
static struct Singleton* Instance();
void NextState(struct Singleton* singleton);
void PrintState(struct Singleton* singleton);
void Destroy_Singleton();

char init_state[] = "initial state";
char second_state[] = "second state";
char third_state[] = "third state";

/* Singleton Implementation */
static struct Singleton* g_instance = NULL;

struct Singleton* Singleton_Instance() {
    char* state = NULL;
    if (g_instance != NULL) {
        return;
    }
    g_instance = (struct Singleton*)malloc(sizeof(struct Singleton));
    state = (char*)malloc(sizeof(init_state)+1);
    strcpy(state, init_state);
    g_instance->state_ = state;
    return g_instance;
}

void Destroy_Singleton() {
    if (g_instance == NULL) {
        return;
    }
    free(g_instance->state_);
    g_instance->state_ = NULL;
    free(g_instance);
    g_instance = NULL;
    return;
}

void NextState(struct Singleton* singleton) {
    char* state = NULL;

    state = singleton->state_;
    if (strcmp(state, init_state) == 0) {
        free(state);
        state = (char*)malloc(sizeof(second_state)+1);
        strcpy(state, second_state);
    } else if (strcmp(state, second_state) == 0) {
        free(state);
        state = (char*)malloc(sizeof(third_state)+1);
        strcpy(state, third_state);
    } else if (strcmp(state, third_state) == 0) {
        free(state);
        state = (char*)malloc(sizeof(init_state)+1);
        strcpy(state, init_state);
    }
    singleton->state_ = state;
    return;
}

void PrintState(struct Singleton* singleton) {
    printf("%s\n", singleton->state_);
    return;
}


int main() {
    /* Client Code には g_instance を意識させない */
    static struct Singleton* theSingleton = NULL;
    static struct Singleton* anotherSingleton = NULL;

    theSingleton = Singleton_Instance();
    printf("theSingleton: ");
    PrintState(theSingleton);

    NextState(theSingleton);
    printf("theSingleton: ");
    PrintState(theSingleton);

    anotherSingleton = Singleton_Instance();
    printf("anotherSingleton: ");
    PrintState(anotherSingleton);

    NextState(anotherSingleton);
    printf("anotherSingleton: ");
    PrintState(anotherSingleton);

    printf("theSingleton: ");
    PrintState(theSingleton);

    Destroy_Singleton();

    return 0;
}


改訂履歴

2009.2.21 C言語版を追加
     
     

ご意見、ご感想はこちらまで。

Copyright(C) 2000-2009 Yoshinori Oota All rights reserved.

本ホームページのリンクは自由です。複製、転載される場合は、必ず著者までご連絡をください。