La seguente spiegazione è piuttosto dettagliata, ma penso che se avessi semplificato il problema non sarebbe stata data una risposta adeguata.
Sto lavorando a un sistema di scripting per un gioco (per gli utenti finali piuttosto che per l'uso interno degli sviluppatori). Il gioco ha sia modalità singleplayer che multiplayer. Esiste una classe Script
di base, ereditata da MultiplayerScript
e SingleplayerScript
(in modo nativo, gli script multiplayer avranno determinate funzioni / API per più giocatori - pensi agli indirizzi IP dei giocatori, ecc.)
Ho anche il codice per caricare e gestire gli script; il codice è largamente condiviso tra le modalità MP e SP (ad esempio, l'analisi del comando load
emesso dall'utente), ma ci sono alcune piccole differenze: la directory in cui il codice deve cercare gli script, il modo in cui uno script viene istanziato ( a seconda della modalità, desidero istanziare SingleplayerScript
o MultiplayerScript
). Mi viene in mente il concetto di ereditarietà - forse una base ScriptManager
con tutto il codice comune più alcuni metodi astratti da sovrascrivere da sottoclassi specifiche della modalità che implementano funzionalità specifiche. Ad esempio:
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);
}
Il problema è che il concetto ScriptManager
è intrinsecamente globale; ad esempio, manterrà un elenco di tutti gli script attualmente caricati (come puntatori alla classe Script
di base). Qualche altro codice comune potrebbe voler accedere a queste informazioni. Tuttavia, se faccio semplicemente una sottoclasse di ScriptManager
per implementare questa specifica funzionalità, dovrò istanziare manualmente MultiplayerScriptManager
da qualche parte nel codice multiplayer, e allo stesso modo per la modalità singleplayer. Ciò significa che il codice condiviso non ha più accesso all'istanza del gestore di script.
Ora, ancora una volta, la prima cosa che mi viene in mente è lo schema singleton, ma non credo che questo si mescoli bene con l'ereditarietà; mentre è possibile , non sono convinto che sia la soluzione più elegante di sempre e visto che non è così esotica problema, mi sento come ci deve essere un modo migliore.
Quanto sopra è semplicemente ciò a cui sono stato in grado di pensare (e respinto in quanto insoddisfacente); la domanda è come risolvere questo problema in modo elegante, non come risolverlo collegando singoletti ed eredità (anche se questo risulta essere il modo migliore, così sia).
La mia piattaforma è C ++ 14, anche se credo che le soluzioni si estenderanno probabilmente anche a C # o Java ecc.