2011-12-19 9 views
6

Estoy implementando un programa en C++ que puede instanciar mediante programación objetos dados un archivo de entrada que proporciona los nombres de clase y argumentos para pasar a los constructores.Patrón de fábrica de C++ con restricción de constructor heterogéneo

Las clases se derivan de una clase base común, pero su firma de constructor varía.

Se declaran de la siguiente manera:

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

Los tipos de argumentos no tienen que ser de tipo int, de hecho, podrían ser cualquier tipo incorporado o compleja, de tipo personalizado.

La entrada del programa podría tener este aspecto en forma de JSON:

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

Lectura a través de los documentos de Boost.Functional/Factory parece que se podría solucionar mi problema si no fuera por el hecho de que en mi solicitud la firma constructora varía (la restricción de heterogeneidad). El enfoque de Boost.Function/Factory es normalizar las firmas de los constructores; sin embargo, esto no es posible en mi aplicación.

En un lenguaje dinámico como Python, esto sería bastante trivial: obj = klass(*args) donde klass = Class1 y args = ["arg11, "arg12"].

Entonces, ¿cómo se podría implementar el patrón de fábrica con la restricción heterogénea en C++?

¿Hay otras bibliotecas además de Boost que he pasado por alto que pueden ser de ayuda?

¿Es posible implementar esto de modo que la única dependencia sea la biblioteca estándar (es decir, no Boost)?

Además, en el caso en que un argumento de constructor es de un tipo complejo, por lo que debe construirse especialmente a partir de su representación JSON, ¿cómo afecta la complejidad del problema?

+0

Para referencia futura, lo opuesto a la homogénea es heterogénea –

+2

Hola Seth, 'homogéneo' también es una palabra válida según el diccionario Merriam-Webster y tiene un significado similar a 'heterogénea'. Elegí la primera porque esa también es la opción de la documentación de Boost.Function/Factory (ver el enlace en mi publicación). –

+0

Sí, lo sé, puede agregar "in" o "un" a casi cualquier palabra y seguirá siendo una palabra. Simplemente suena raro. –

Respuesta

1

Para lograr lo que quiere que se necesita, en algún momento de su código, un gigante switch -statement para decidir qué clase de construcción basada en el nombre (en realidad, una switch no funcionará, porque no puede encender las cadenas, más como un muy largo if - else if).

Además, parece que la representación que muestra no contiene ninguna información sobre el tipo de los argumentos del constructor. Esto podría ser un problema si tiene una clase que tiene múltiples constructores que se pueden llamar con la misma cantidad de argumentos.

Al final, creo que es mejor si vas con algo como @selbies answer, pero utiliza la generación de código para generar el código de construcción para ti.

+0

Gracias @bjorn & selbie. Para mi caso de uso, la mejor respuesta es la generación de código. Mi generador de código es ~ 100 líneas de Python y genera _aproximadamente_ funciones de fábrica válidas. Es decir. Tengo que masajear algo del código generado. Incluso con un generador de código menos que perfecto, he sido increíblemente productivo en el cumplimiento de esta tarea. Puede que valga la pena ampliar Boost.Functional/Factory para mi caso de uso. Para ser explorado más tarde. :) FYI: biblioteca de análisis de encabezado C++: [CppHeaderParser library] (https://bitbucket.org/senex/cppheaderparser/src), que es adecuada para mis necesidades. –

5

¿Ha considerado tener un método de fábrica para cada clase que sepa cómo construir el objeto a partir de una "matriz" de parámetros leídos del archivo.

Es decir:

// 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

Definitivamente he considerado una opción similar a esta ... es decir, pasar el objeto JSON a una función de fábrica estática y hacer que devuelva la instancia. El problema es que la base de código con la que trato tiene más de 100 de estas clases en este momento y sigue creciendo. Entonces, aunque esta sería sin duda una solución posible, dudo en llamarla ideal en este momento. –

Cuestiones relacionadas