Wednesday, December 4, 2019

Менеджер данных (одиночка) в си++.

В программировании часто приходится решать задачу по управлению данными, в числе которых могут быть игровые объекты, текстуры, состояния, компоненты и т.д. Обычно нам нужно их где-то хранить, иметь возможность их создавать, добавлять в хранилище, удалять из хранилища, уничтожать, обрабатывать. Наши данные представлены собственными классами (возможно со своей иерархией наследования) и логично предположить, что для управления этими классами нам понадобится новый отдельный класс со своими методами призванными решать задачи по управлению нашими данными и назовем мы его например IntManager.
 
Данные (int) будем хранить в векторе. Методами для управления пусть будут метод для добавления данных в вектор и метод для печати количества элементов в векторе. Дальше нам понадобятся конструктор и деструктор и тут мы должны для себя понять, нужны ли нам несколько таких менеджеров одновременно. Очевидно, что нет, мы не хотим создать условия, при которых можем получить одновременный доступ из нескольких мест к одним и тем же данным. Значит нам нужно придумать способ наличия в системе только одного менеджера и такой способ есть – использовать паттерн Одиночка (singleton). Этот подход определяет несколько правил, следуя которым мы решим нашу задачу.
 
Сначала нам нужно закрыть доступ к конструктору и деструктору(а также к копирующему конструктору и к копирующему оператору присваивания), а обращение к объекту нашего менеджера осуществлять через статический метод Instance(), который будет создавать при необходимости объект нашего менеджера, а при его наличии возвращать статический указатель на него. Статический метод позволит нам обращаться к этому методу без наличия объекта класса, а статический указатель будет храниться в статической памяти, т. е. независимо. Не забываем, что статические члены класса нужно проинициализировать за пределами класса, в нашем случае нулем. Про статическую память можно почитать в одном из моих предыдущих постов.

#include <iostream>
#include <vector>

class IntManager {
public:
    static IntManager *Instance() {
        if (s_pInstance == nullptr) {
            s_pInstance = new IntManager();
            return s_pInstance;
        }
        return s_pInstance;
    }


    void AddInt(int _i){
        ints.push_back(_i);
    }

    void GetSize(){
        std::cout << "Size: " << ints.size() << std::endl;
    }

private:
    IntManager() = default;
    virtual ~IntManager() = default;

    IntManager(const IntManager &);
    IntManager &operator=(const IntManager &);

    static IntManager *s_pInstance;
    std::vector<int> ints;
};

IntManager* IntManager::s_pInstance = nullptr;

int main() {
    IntManager::Instance()->AddInt(1);
    IntManager::Instance()->AddInt(2);
    IntManager::Instance()->GetSize();

    return 0;
}

Output:
>>Size: 2

Перегуд В.