2011-12-19 5 views
6

Sto implementando un programma C++ che può istanziare a livello di codice oggetti dati un file di input che fornisce i nomi delle classi e gli argomenti da passare ai costruttori.Modello di fabbrica in C++ con vincolo di costruzione eterogeneo

Le classi derivano da una classe base comune ma la loro firma del costruttore varia.

Essi sono dichiarati come segue:

class Base { ... } 
class Class1 : Base { Class1(int a1, int a2); } 
class Class2 : Base { Class2(int a1, int a2, int a3); } 
... and so on... 

I tipi di argomenti non devono essere Int di, in realtà potrebbe essere qualsiasi tipo built-in o complessi, tipo personalizzato.

L'ingresso programma potrebbe apparire così in forma JSON:

[ 
    { "Class1": ["arg11", "arg12"] }, 
    { "Class2": ["arg21", "arg22", "arg23"] }, 
    ...and so on... 
] 

Leggendo la documentazione per Boost.Functional/Factory sembra che potrebbe risolvere il mio problema se non fosse per il fatto che nella mia richiesta la firma del costruttore varia (il vincolo di eterogeneità). L'approccio Boost.Function/Factory è quello di normalizzare le firme del costruttore, tuttavia ciò non è possibile nella mia applicazione.

In un linguaggio dinamico come Python, questo sarebbe piuttosto banale: obj = klass(*args) dove klass = Class1 e args = ["arg11, "arg12"].

Quindi, come si dovrebbe implementare lo schema di fabbrica con il vincolo eterogeneo in C++?

Ci sono altre librerie oltre a Boost che ho trascurato che potrebbero essere d'aiuto?

È possibile implementarlo in modo tale che l'unica dipendenza sia la libreria standard (cioè senza Boost)?

Inoltre, nel caso in cui un argomento del costruttore sia di tipo complesso in modo che debba essere appositamente costruito dalla sua rappresentazione JSON, in che modo influisce sulla complessità del problema?

+0

Per riferimento futuro, il contrario di omogenea è eterogenea –

+2

Hey Seth, 'disomogenea' è anche una parola valida secondo il dizionario Merriam-Webster ed è simile al significato di 'eterogenea'. Ho scelto il primo perché è anche la scelta della documentazione di Boost.Function/Factory (vedi il link nel mio post). –

+0

Sì, lo so, è possibile aggiungere "in" o "un" a quasi tutte le parole e sarà ancora una parola. Sembra strano. –

risposta

1

per ottenere ciò che si vuole è necessario, ad un certo punto nel codice, un gigante switch -affermazione per decidere quale classe di costruire basato sul nome (in realtà, un switch non funzionerà, perché non è possibile accendere stringhe - più come un lunghissimo if - else if).

Inoltre, sembra che la rappresentazione mostrata non contenga alcuna informazione sul tipo degli argomenti del costruttore. Questo potrebbe essere un problema se si dispone di una classe con più costrutti chiamabili con lo stesso numero di argomenti.

Alla fine, penso che sia meglio se si utilizza qualcosa come @selbies answer, ma si usi la generazione del codice per generare il codice di costruzione.

+0

Grazie a @bjorn e selbie. Per il mio caso d'uso, la risposta migliore è la generazione del codice. Il mio generatore di codice è ~ 100 righe di Python e genera _approximately_predefinite funzioni di fabbrica. Cioè Devo massaggiare un po 'del codice generato. Anche con un generatore di codice meno che perfetto, sono stato incredibilmente produttivo nel portare a termine questo compito. Potrebbe valere ancora la pena estendere Boost.Functional/Factory per il mio caso d'uso. Per essere esplorato in seguito. :) FYI: libreria di analisi dell'intestazione C++: [libreria CppHeaderParser] (https://bitbucket.org/senex/cppheaderparser/src), che è adeguata alle mie esigenze. –

5

Avete considerato di avere un metodo factory per ogni classe che sa come costruire l'oggetto da un "array" di parametri letti dal file.

Cioè:

// declared "static" in header file 
Class1* Class1::FactoryCreate(int argc, const char** argv) 
{ 
    if (argc != 2) 
     return NULL; // error 

    int a1 = atoi(argv[0]); 
    int a2 = atoi(argv[1]); 
    return new Class1(a1, a2, a3); 
} 

// declared "static" in header file 
Class2* Class2::FactoryCreate(int argc, const char** argv) 
{ 
    if (argc != 3) 
     return NULL; // error 
    int a1 = atoi(argv[0]); 
    int a2 = atoi(argv[1]); 
    int a3 = atoi(argv[2]); 
    return new Class2(a1, a2, a3); 
} 
+0

Ho certamente considerato un'opzione simile a questa ... per passare l'oggetto JSON a una funzione di fabbrica statica e farlo restituire l'istanza. Il problema è che la base di codice con cui ho a che fare ha oltre 100 classi di questo tipo e sta crescendo. Quindi, mentre questa sarebbe certamente una soluzione possibile, esita a chiamarla ideale al momento. –