Sto lavorando a un software che genera dati di configurazione per determinati hardware e che al momento deve essere adattato ogni volta che l'hardware viene rilasciato in una nuova versione da un'azienda esterna (ciò accade circa due volte all'anno). Il mio compito attuale è quello di introdurre un'interfaccia plugin in modo che l'intera applicazione non debba essere ricompilata e ripubblicata ogni volta.
Attualmente, l'iniezione di nuove funzionalità o la sostituzione della funzionalità predefinita adattata è già possibile in fase di esecuzione. Tuttavia, esiste un enum
centrale che contiene tutte le diverse versioni al suo interno e impedisce che ampie parti del codice vengano separate dall'eseguibile.
L'enum sembra un po 'come questo:
enum class HardwareVersion
{
Stage1_Base, // corresponds to version 5.11.37
Stage1_Extensions, // corresponds to version 5.12.01
Stage2_Base, // corresponds to version 8.00.00
Stage2_ABC_Extensions, // corresponds to version 8.03.20
Stage2_DEF_Extensions // corresponds to version 9.01.00
}
Nota: i nomi come "Stage 1 Base" sono termini che vengono solitamente usati quando si discute con la gestione del progetto o il cliente, quindi sono stati utilizzati anche nel codice.
Gli utenti del software devono visualizzare e modificare i dati per ogni fase possibile e generare i rispettivi dati di configurazione per la versione hardware di interesse (utilizzano contemporaneamente diverse versioni hardware). Per questo motivo, il software ha diverse parti di codice simili al seguente (codice teorico in modo da ottenere l'idea):
// This would be in a plugin
void addContent( HardwareVersion currentStage ) /* override */
{
if (currentStage < Stage2_Base) return;
// add stage 2 content
...
}
e
// This would be in a plugin as well
void initialize() /* override */
{
_someFactory->register( HardwareVersion::Stage2_Base, new Stage2SubcontrolFactory() );
}
// This would be somewhere in the core application
std::shared_ptr<Subcontrol> createSubcontrol( HardwareVersion currentStage )
{
return getFactory( currentStage )->createSubcontrol();
}
Ora potremmo semplicemente sostituire enum
di typedef int
e perdere tutta la sicurezza di tipo ecc. Potremmo anche usare GUID e perdere tutta la leggibilità e rendere il debug davvero difficile.
Entrambe le soluzioni si sentono davvero male. Questo (finalmente) porta alla domanda:
Che cosa dovresti sostituire con un'enumerazione se i valori devono essere forniti dai plugin?
[Modifica:] Per renderlo meno soggettivo: i due principali punti critici per le soluzioni sono l'alta manutenibilità (questo per me significa leggibilità) e l'alta stabilità quando si aggiungono nuovi plugin.