Chciałbym używać wszędzie w kodzie Config
jako singleton i pewnego rodzaju standard , jednak chciałbym moc w main()
podmienić aby singleton tworzył obiekt klasy która jest potomkiem Config
np. aby dane zapisywały się w SqLite albo w jakimś innym formacie
Czy można to zrobić lepiej niż poniższym przykładzie:
#include <clocale>
#include <iostream>
#include <string>
#include <map>
#include <functional>
class Config
{
private:
std::map<std::string, int> data;
static inline Config* _instance{nullptr};
static inline std::function<Config*()> createInstance{nullptr};
public:
friend class ConfigSqLite;
Config(Config const&) = delete;
Config& operator=(Config const&) = delete;
static Config* instance()
{
if(!_instance)
{
if(createInstance)
{
_instance = createInstance();
}
else
{
_instance = new Config();
}
}
return _instance;
}
virtual int saveInt(const std::string &key, int value)
{
std::cout << "Config::saveInt\n";
data[key] = value;
return value;
}
virtual int readInt(const std::string &key)
{
std::cout << "Config::readInt\n";
return data[key];
}
static void registerCreateInstance(std::function<Config*()> function)
{
createInstance = function;
}
private:
Config() {}
};
class ConfigSqLite: public Config
{
int saveInt(const std::string &key, int value) override
{
// TODO
std::cout << "ConfigSqLite::saveInt\n";
return value;
}
int readInt(const std::string &key) override
{
// TODO
std::cout << "ConfigSqLite::readInt\n";
return 0;
}
public:
ConfigSqLite(std::string databaseName):Config()
{
// TODO
}
};
int main(int, char**){
std::string CONFIG_WIDTH{"width"};
// tworzac sigleton Config , naprawde utworzy sie obiekt ConfigSqLite
Config::registerCreateInstance([](){
return new ConfigSqLite("database.sqlite");
});
Config::instance()->saveInt(CONFIG_WIDTH, 100);
std::cout << Config::instance()->readInt(CONFIG_WIDTH);
}