Pregunta

No sé si hay un nombre oficial para esto, pero he estado jugando con lo que me gusta llamar la "fábrica propia". modelo. Básicamente, es cuando una clase base abstracta actúa como una fábrica por sí misma. Déjame explicarte:

Tengo objetos Foo y objetos Bar en mi sistema, que se utilizan a través de las interfaces FooInterface y BarInterface. Necesito darles a mis clientes el tipo correcto de Foo and Bar. La decisión de qué objeto Foo concreto crear se toma en tiempo de compilación. Por ejemplo, si compila en win32, solo desea crear objetos Win32Foo, y si compila en OSX solo quiere crear objetos OSXFoo y así sucesivamente. Pero, la decisión de qué objeto Bar concreto crear se toma en tiempo de ejecución, en función de una cadena de clave.

Ahora, mi pregunta es sobre la mejor manera de implementar este esquema. Una forma en que se me ocurre utiliza fábricas regulares:

shared_ptr<FooInterface> foo = FooFactory::create();
shared_ptr<BarInterface> happyBar = BarFactory::create("Happy");
shared_ptr<BarInterface> sadBar = BarFactory::create("Sad");

Otra forma es usar lo que yo llamo "auto-fábricas":

shared_ptr<FooInterface> foo = FooInterface::create();
shared_ptr<BarInterface> happyBar = BarInterface::create("Happy");
shared_ptr<BarInterface> sadBar = BarInterface::create("Sad");

¿Cuáles son los pros y los contras de cada enfoque, tanto desde el punto de vista de la usabilidad como desde el punto de vista arquitectónico?

¿Fue útil?

Solución

Las fábricas tienen dos usos comunes:

1) Decidir el tipo polimórfico dinámico en tiempo de ejecución, según los parámetros y / o el estado global (como la configuración). Tu patrón hace esto.

2) Inyección de dependencia: en lugar de usar una función estática para crear objetos, use un objeto de fábrica, de modo que el llamador pueda configurar el tipo de objeto devuelto, pasando cualquier fábrica que desear. Ninguno de estos patrones proporciona esto. Además, su segundo patrón ni siquiera permite la inyección de dependencia estática (al tener funciones de plantilla que toman una clase de fábrica como parámetro de plantilla), porque la interfaz y la fábrica son las mismas.

Entonces, una estafa de su patrón (y de sus fábricas regulares) es que la inyección de dependencia no es realmente compatible. Hay una y solo una función para llamar para obtener un objeto que es un FooInterface, y es FooInterface :: create (). No discutiré por qué la inyección de dependencia es útil, solo señale que si construye de esta manera, no puede usarla.

Otros consejos

Haría una mejora:

shared_ptr<FooInterface> foo = Factory<FooInterface>::create();
shared_ptr<BarInterface> happyBar = Factory<BarInterface>::create("Happy");
shared_ptr<BarInterface> sadBar = Factory<BarInterface>::create("Sad");

Declararías:

template <class I>
struct Factory { };

Y luego, para cada interfaz que necesita una fábrica, haría esto:

template <>
struct Factory<FooInterface>
{
    static FooInterface create();
};

Esto le permite mantener la implementación de fábrica separada de la declaración de la interfaz, pero aún utilizando el sistema de tipos para vincularlos en tiempo de compilación.

Por lo general, las fábricas son responsables de crear objetos de jerarquías de clase completas. Entonces, en su ejemplo, tendría un Win32Factory, OSXFactory, etc. Una ventaja de esto es que debe seleccionar la implementación específica (win32 / unix / etc.) solo una vez, durante la creación de fábrica, pero si usa interfaces de clase, tiene para proporcionar la información del sistema operativo todo el tiempo.

Si solo tiene dos clases (Foo y Bar), no estoy seguro, si vale la pena crear fábricas para ellos y no solo usar el método create de las interfaces.

Ah, y cuando una interfaz tiene un método para crear objetos de su tipo, se llama método de fábrica patrón .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top