The following explanation is rather detailed, but I think if I simplified the problem at hand no proper answer could be given.
I'm working on a scripting system for a game (for end users rather than internal developer usage). The game has both singleplayer and multiplayer modes. There is a base Script
class, inherited by MultiplayerScript
and SingleplayerScript
(natually, multiplayer scripts will have certain multiplayer-specific functions/APIs - think player IP addresses etc).
I also have code to load and manage the scripts; the code is largely shared between MP and SP modes (parsing the load
command issued by the user, for instance), but there are some minor differences - the directory where the code should look for scripts, the way a script is instantiated (depending on the mode, I will want to instantiate SingleplayerScript
or MultiplayerScript
). The concept of inheritance springs to mind - perhaps a base ScriptManager
with all the common code plus a few abstract methods to be overridden by mode-specific subclasses that implement specific functionality. As an example:
void ScriptManager::load(const std::string& command)
{
const auto name = getNameFromCommand(command);
// This is a virtual method that returns an instantiated script object
const std::shared_ptr<Script> script = instantiateFromName(name);
script->initialize();
scripts.push(script);
}
The issue is that the ScriptManager
concept is inherently global; it will hold, for example, a list of all presently loaded scripts (as pointers to the base Script
class). Some other common code might want to access this information. However, if I simply subclass ScriptManager
to implement this specific functionality, I will need to manually instantiate MultiplayerScriptManager
somewhere in multiplayer code, and likewise for the singleplayer mode. This means shared code no longer has access to the script manager instance.
Now, again, the first thing that springs to mind is the singleton pattern, but I don't believe this mixes well with inheritance; while it's possible, I'm not convinced it's the most elegant solution ever, and given that this isn't such an exotic problem, I feel like there has to be a better way.
The above is simply what I was able to think of (and rejected as unsatisfactory); the question is how to solve this problem in an elegant way, not how to solve it by connecting singletons and inheritance (although if that turns out to be the best way, so be it).
My platform is C++14, although I believe the solutions will probably extend to C# or Java etc as well.