making - Factory Pattern en C++-¿haciendo esto correctamente?
factory pattern uml (5)
Soy relativamente nuevo en "patrones de diseño" como se los denomina en un sentido formal. No he sido profesional por mucho tiempo, así que soy bastante nuevo en esto.
Tenemos una clase base de interfaz virtual pura. Esta clase de interfaz obviamente proporciona la definición de qué funcionalidad deben hacer sus hijos derivados. El uso actual y la situación en el software dictan qué tipo de hijo derivado queremos usar, por lo que recomendé crear un contenedor que comunique qué tipo de hijo derivado queremos y devolver un puntero de Base que apunta a un nuevo objeto derivado. Este envoltorio, a mi entender, es una fábrica.
Bueno, un colega mío creó una función estática en la clase Base para actuar como la fábrica. Esto me causa problemas por dos razones. En primer lugar, parece romper la naturaleza de la interfaz de la clase Base. Me parece mal que la interfaz en sí misma necesite tener conocimiento de los niños derivados de ella.
En segundo lugar, causa más problemas cuando trato de volver a utilizar la clase Base en dos proyectos de Qt diferentes. Un proyecto es donde estoy implementando la primera (y probablemente solo real implementación para esta clase ... aunque quiero usar el mismo método para otras dos características que tendrán varias clases derivadas diferentes) clase derivada y la segunda es la real aplicación donde mi código eventualmente será utilizado. Mi colega ha creado una clase derivada para actuar como un probador para la aplicación real mientras codifico mi parte. Esto significa que tengo que agregar sus encabezados y archivos cpp a mi proyecto, y eso parece incorrecto ya que ni siquiera estoy usando su código para el proyecto mientras implemento mi parte (pero usará el mío cuando esté terminado) )
¿Estoy en lo cierto al pensar que la fábrica realmente necesita ser una envoltura alrededor de la clase Base en lugar de la Base que actúa como la fábrica?
Cuando la interfaz solo sirve para ocultar los detalles de la implementación y solo habrá una implementación de la interfaz Base, podría estar bien acoplarlos. En ese caso, la función de fábrica es solo un nuevo nombre para el constructor de la implementación real.
Sin embargo, ese caso es raro. Excepto cuando se haya diseñado explícitamente tener una única implementación, es mejor asumir que existirán múltiples implementaciones en algún momento, aunque solo sea para la prueba (como descubriste).
Por lo general, es mejor dividir la parte de Fábrica en una clase separada.
NO quieres usar tu clase de interfaz como clase de fábrica. Por un lado, si se trata de una verdadera clase de interfaz, no hay implementación. En segundo lugar, si la clase de interfaz tiene alguna implementación definida (además de las funciones virtuales puras), crear un método de fábrica estático obliga ahora a la clase base a recompilarse cada vez que agrega una implementación de clase hija.
La mejor manera de implementar el patrón de fábrica es tener su clase de interfaz separada de su fábrica.
Un ejemplo muy simple (e incompleto) está a continuación:
class MyInterface
{
public:
virtual void MyFunc() = 0;
};
class MyImplementation : public MyInterface
{
public:
virtual void MyFunc() {}
};
class MyFactory
{
public:
static MyInterface* CreateImplementation(...);
};
No es raro ver las funciones de miembro de la fábrica en una clase, pero hace que mis ojos sangren. A menudo, su uso se ha mezclado con la funcionalidad del idioma de constructor nombrado . Mover la (s) función (es) de creación a una clase de fábrica separada le comprará más flexibilidad también para intercambiar fábricas durante la prueba.
Sí, un método de fábrica estático en la interfaz (clase base) requiere que tenga conocimiento de todas las instancias posibles. De esta forma, no obtendrá la flexibilidad que el patrón del Método de Fábrica pretende ofrecer.
La fábrica debe ser una pieza de código independiente, utilizada por el código del cliente para crear instancias. Tienes que decidir en algún lugar de tu programa qué instancia concreta crear. El Método de Fábrica le permite evitar que la misma decisión se extienda a través del código de su cliente. Si luego desea cambiar la implementación (o, por ejemplo, para realizar pruebas), tiene solo un lugar para editar: puede ser, por ejemplo, un cambio global simple, mediante compilación condicional (generalmente para pruebas) o incluso a través de un archivo de configuración de inyección de dependencia.
Tenga cuidado con la forma en que el código del cliente comunica qué tipo de implementación quiere: esa no es una forma poco común de reintroducir las dependencias que las fábricas deben ocultar.
Tendría que estar de acuerdo contigo. Probablemente uno de los principios más importantes de la programación orientada a objetos es tener una responsabilidad única por el alcance de un fragmento de código (ya sea un método, clase o espacio de nombres). En su caso, su clase base sirve para definir una interfaz. Agregar un método de fábrica a esa clase, viola ese principio, abriendo la puerta a un mundo de ... problemas.