Создайте статический член, который указывает на текущий класс, ограничьте использование конструкторов для создания класса, сделав их private, и создайте открытую статическую функцию-член, которая будет использоваться для доступа к единственному статическому экземпляру. Пример 8.9 демонстрирует, как это делается.

Пример 8.9. Создание singleton-класса

#include

using namespace std;

class Singleton {

public:

 // С помощью этого клиенты получат доступ к единственному экземпляру

 static Singleton* getInstance();

 void setValue(int val) {value_ = val;}

 int getValue() {return(value_);}

protected:

 int value_;

private:

 static Singleton* inst_;   // Единственный экземпляр

 Singleton() : value_(0) {} // частный конструктор

 Singleton(const Singleton&);

 Singleton& operator=(const Singleton&);

};

// Определяем указатель

static Singleton Singleton* Singleton::inst_ = NULL;

Singleton* Singleton::getInstance() {

 if (inst_ == NULL) {

  inst_ = new Singleton();

 }

 return(inst_);

}

int main() {

 Singleton* p1 = Singleton::getInstance();

 p1->setValue(10);

 Singleton* p2 = Singleton::getInstance();

 cout << "Value = " << p2->getValue() << '\n';

}

Обсуждение

Существует множество ситуаций, когда требуется, чтобы у класса существовал только один экземпляр. Для этой цели служит шаблон Singleton. Выполнив несколько простых действий, можно реализовать singleton-класс в С++.

Когда принимается решение, что требуется только один экземпляр чего-либо, то на ум сразу должно приходить ключевое слово static. Как было сказано в рецепте 8.5, переменная-член static — это такая, которая может иметь в памяти только один экземпляр. Для отслеживания единственного объекта singleton-класса используйте переменную-член static, как сделано в примере 8.9.

private:

 static Singleton* inst_;

Чтобы клиентский код ничего про нее не знал, сделайте ее private. Убедитесь, что в файле реализации она проинициализирована значением NULL.

Singleton* Singleton::inst_ = NULL;

Чтобы запретить клиентам создавать экземпляры этого класса, сделайте конструкторы private, особенно конструктор по умолчанию.

private:

Singleton() {}

Таким образом, если кто-то попробует создать в куче или стеке новый singleton-класс, то он получит дружественную ошибку компилятора.

Теперь, когда статическая переменная для хранения единственного объекта Singleton создана, создание объектов Singleton ограничено с помощью ограничения конструкторов; все, что осталось сделать, — это предоставить клиентам способ доступа к единственному экземпляру объекта Singleton. Это делается с помощью статической функции-члена.

Singleton* Singleton::getInstance() {

 if (inst_ == NULL) {

  inst_ = new Singleton();

 }

 return(inst_);

}

Посмотрите, как это работает. Если указатель static Singleton равен NULL, создается объект. Если он уже был создан, то возвращается его адрес. Клиенты могут получить доступ к экземпляру Singleton, вызвав его статический метод.

Singleton* p1 = Singleton::getInstance();

И если вы не хотите, чтобы клиенты работали с указателями, то можно возвращать ссылку.

Singleton& Singleton::getInstance() {

 if (inst_ == NULL) {

  inst_ = new Singleton();

 }

 return(*inst_);

}

Важно здесь то, что в обоих случаях клиентам запрещено создавать экземпляры объекта Singleton, и создается единый интерфейс, который предоставляет доступ к единственному экземпляру.

Смотри также

Рецепт 8.3.

<p>8.10. Создание интерфейса с помощью абстрактного базового класса</p>Проблема

Требуется определить интерфейс, который будет реализовываться производными классами, но концепция этого интерфейса является абстракцией и не должна наследоваться сама по себе.

Решение
Перейти на страницу:

Похожие книги