It started with a simple log manager. Then I wanted to implement more features, for example printing the name of the component that send a message. Later on, I can think of giving each component that prints log messages it's own text color in the terminal and options to mute or solo single modules.
Therefore, the manager needs the identity of the component that called its methods. So I decided to wrap the manager with an instance for every component. It tunnels function calls to the manager together with the name of the component.
#include <iostream>
#include <string>
#include <memory>
#include <unordered_map>
using namespace std;
////////////////////////////////////////////////////////////////
// Manager declaration
////////////////////////////////////////////////////////////////
class manager {
public:
class instance;
instance &get_instance(string name);
void print(string sender, string message);
private:
unordered_map<string, unique_ptr<instance>> m_instances;
};
////////////////////////////////////////////////////////////////
// Instance declaration
////////////////////////////////////////////////////////////////
class manager::instance {
public:
instance(string name, manager &manager);
void print(string message);
private:
string m_name;
manager &m_manager;
};
////////////////////////////////////////////////////////////////
// Manager implementation
////////////////////////////////////////////////////////////////
manager::instance &manager::get_instance(string name) {
if (m_instances.find(name) == m_instances.end())
m_instances[name] = unique_ptr<instance>(new instance(name, *this));
return *m_instances[name].get();
}
void manager::print(string sender, string message) {
cout << sender << ": " << message << "." << endl;
}
////////////////////////////////////////////////////////////////
// Instance implementation
////////////////////////////////////////////////////////////////
manager::instance::instance(string name, manager &manager) : m_name(name),
m_manager(manager) {}
void manager::instance::print(string message) {
m_manager.print(m_name, message);
}
////////////////////////////////////////////////////////////////
// Main function
////////////////////////////////////////////////////////////////
int main() {
manager m;
m.get_instance("Window").print("Open up");
m.get_instance("Asset").print("Load textures");
return 0;
}
Here is a working example of my code. What do you think about the class structure and architecture? Is there an easier or more expressive way? I'd like to get feedback and improve the code structure before implementing other managers the same way.