2009-06-22 22 views
5

Estaba trabajando con el código de Java que supuestamente usa el patrón Factory, pero no estoy completamente convencido por el patrón.Patrón de fábrica en Java

Mi código hace esto:

// the factory 
class SomeFactoryImpl { 
    Set<SomeClass> getSomeListOfObjects(); 
} 

Y en alguna parte del código:

{ ... 
    SomeFactory factory = new SomeFactoryImpl(); 
    Set<SomeClass> list = factory.getSomeListOfObjects(); 
} 

El punto que estoy pensando es, si las clases de fábrica no tienen un método estático crear() , entonces uno necesitará instanciar una fábrica, que IMO debería ser tan complejo como instanciar un objeto en sí mismo.

No considero suficiente el argumento de que una fábrica de este tipo puede devolver colecciones de objetos para producir. Siento que puede haber soluciones más limpias, si es necesario crear una instancia de fábrica antes de crear objetos de fábrica.

Creo que es mejor si el método create es un método estático de la clase de fábrica. Pero también estoy seguro de que mi opinión no es completamente "correcta".

Entonces, ¿la comunidad SO puede dar ejemplos donde crear instancias de un objeto Factory es mejor que usar métodos estáticos de creación?

Además, me encontré con una respuesta a una pregunta similar, que se enumeran estos enlaces y la respuesta: lo que necesito saber con claridad la diferencia entre FactoryMethodPattern, FactoryMethod y CreationMethod con ejemplos de código.

+0

Es bastante común en Java APIs como TRAX tener un método newInstance estática() de la clase de fábrica (por ejemplo TransformerFactory.newInstance()), y luego llama a createTransformer() en el resultado. – skaffman

Respuesta

5

El uso de una instancia de una fábrica muestra los beneficios reales cuando se combina con la inyección de dependencia.

Así que en su ejemplo, en lugar de:

{ ... 
    SomeFactory factory = new SomeFactoryImpl(); 
    Set<SomeClass> list = factory.getSomeListOfObjects(); 
} 

Tendrías:

public ThisClass(SomeFactory someFactory) { 
    this.factory = someFactory; 
} 

luego ...

{ ... 
    Set<SomeClass> list = factory.getSomeListOfObjects(); 
} 

Algunos puntos:

  • En esta circunstancia, su clase no tiene ninguna referencia a una fábrica de concreto, y no necesita saber sobre SomeFactoryImpl, solo conoce el SomeFactory resumido.
  • En este caso, la instancia de fábrica que se está transfiriendo se puede configurar en una instancia, en lugar de en una base estática, que tiende a ser (en mi opinión) una forma más agradable de manejarlo. Si puede hacer que la instancia de fábrica sea inmutable, entonces realmente puede reducir las preocupaciones de múltiples subprocesos.
  • Tener una llamada estática para darle una instancia no es mucho mejor, la referencia a la clase que la crea sigue siendo un detalle concreto de la implementación, está más arriba, aunque eso puede hacer que sea lo suficientemente alto como para resolver su problema .

Sé que esto sólo se refiere a un subconjunto de su pregunta ...

+1

+1 Oh, sí ... combine esto con un marco DI y las pruebas se convertirán en un juego de niños. ¡Gracias! – jrharshath

1

Supongo que un método estático para la creación de objetos es el enfoque más popular, pero también hay algunos casos de uso donde la creación de una instancia de fábrica tiene sentido. Por ejemplo, si desea combinarlo con un registro (donde se debe permitir que varios registros coexistan).

Además, si la fábrica se basa en información dinámica de contexto (conexiones de bases de datos, ...), en mi opinión, es mejor dejar que una instancia de fábrica se encargue de esto.

1

Primero de todo lo que se está olvidando el objetivo principal del patrón de la fábrica, que abrió el libro de la banda de los cuatro, y se afirma:

"Definir una interfaz para crear un objet, pero vamos subclases decidir qué clase para instanciar. Factory Method permite que una clase difiera la instanciación a subclases ".

Esto significa que realmente define una interfaz, por lo que SomeFactoryImpl debería implementar una interfaz definida en otro lugar. Esto es útil cuando tienes muchos objetos que necesitan ser instanciados pero no te interesa qué tipo de objeto son. Por ejemplo, los usé para desarrollar una aplicación de desplazamiento remoto en la que el cliente se descargó a través de la serialización. la definición de algunas clases que no existían en la VM del cliente. Cada clase definió una subclase de JPanel que era su punto de vista específico, pero al llegar al cliente tuve que encontrar la forma de interactuar con estas clases sin conocerlas, así que usé un patrón de fábrica para llamar a la clase de fábrica y dejar que creara mi objeto desconocido (a pesar de ello está extendiendo una subclase de JPanel definida por mí). Otro ejemplo sería la generación de objetos específicos de cada caso para satisfacer sus necesidades. Por ejemplo (como se indica en la página wikipedia relacionada con este patrón de diseño) puede pensar una fábrica que construye objetos y luego otra fábrica para el mismo tipo de objeto pero que se usa para generar "objetos falsos" que fallarán algún tipo de prueba unitaria.

Sin embargo, también puede resolver su problema específico con métodos estáticos, pero piense en dividir la parte que genera elementos de la parte que los utiliza en un proyecto grande. Por supuesto, quién está desarrollando la parte del cliente debería saber qué interfaz de fábrica se usa y saber exactamente esto para usar todos los objetos definidos en la otra parte.

Patrón Creación es una especie de patrón de 'instalación' se utiliza sólo para definir versiones personalizadas de constructores sin preocuparse utilizando definición estándar (que tiene el nombre del método igual al nombre de la clase), pero no es nada especial. Solo una forma diferente de publicar objetos ... el patrón de creación en realidad no resuelve ningún tipo de problema específico (excluyendo constructores con el mismo número y tipo de argumentos).

+0

Creo que su SomeFactoryImpl en realidad es una implementación de una interfaz, aunque no se indicó explícitamente. (Bueno, en realidad, la línea SomeFactory factory = new SomeFactoryImpl(); es lo suficientemente explícita). – glmxndr

0

Aquí es por lo que crear instancias de objetos de fábrica

  1. que me permite crear una fábrica, configurarlo (para crear widgets azules contra los widgets rojos etc.) y luego tenerlo disponible para crear mis widgets azules , widgets rojos a pedido. Tenga en cuenta que esto es distinto de tener un RedWidgetFactory, BlueWidgetFactory. La configuración es ortogonal al tipo (s) de objetos que se crean
  2. reduce posibles problemas de enhebrado que puede encontrar con una fábrica (a la que se accede por un método estático) utilizada en todo el sistema. Esto es quizás un poco defensivo, pero he descubierto que es una buena mentalidad tener (especialmente en sistemas de gran tamaño). Por supuesto, depende de cómo se crean los objetos (por ejemplo, ¿su fábrica de crear componentes subyacentes que son compartidos)
+0

Estoy de acuerdo con los problemas de subprocesos y la parte de concurrencia, pero mis poderes de olfato me dicen que RedWidgetFactory es una mejor idea que factory.setProductColor ('red'). ¿Estás/No estás de acuerdo? – jrharshath

+0

Quizás es un mal ejemplo. Pero imagina si tuvieras 10,000 colores. No tendrías una clase de fábrica diferente para cada uno. Mientras que puede tener una clase y fábrica diferente para crear conjuntos discretos de objetos con diferentes comportamientos. –

0

OMI, el código que tiene es muestra de hecho una adecuada del patrón GoF Abstract Factory, incluso si su uso no es completamente óptimo. Si recuerdo correctamente, el libro de GoF describe la relación entre las fábricas (SomeFactory, SomeFactoryImpl) y los productos (SomeClass), pero deja los detalles de las fábricas de instancias abiertas.

Si lo que tienes es una API interna que no va a ser ampliamente utilizada, probablemente lo que tienes es suficiente. De lo contrario, usted podría:

  1. tener otra clase (un "gerente de la fábrica", por así decirlo) seleccionar la implementación de fábrica sobre la base de un parámetro (por ejemplo, el DriverManager de JDBC), u otra información de contexto.
  2. Utilice algún tipo de marco de inyección de dependencia.

Si va con # 1, yo personalmente lo general trato y el modelo después de JDBC, donde:

  • Driver sería la fábrica de resumen
  • Connections, Statements etc son productos
  • DriverManager (no especificado en el libro de GoF explícitamente) es la clase de utilidad que selecciona una fábrica para usted según el URL JDBC pasado en

(En este caso, el DriverManager sigue adelante y crea el producto para usted también, si usa los métodos getConnection(...), como la mayoría lo hace.)

para atar de nuevo a su pregunta, se podría utilizar posiblemente JDBC llamando

new OracleDriver().connect(...) 

Pero como su señalado, esto es sub-óptimo, y algo en contra del propósito de utilizar el patrón de la fábrica abstracta .

Este problema también me molestaba demasiado, hasta que un día me di cuenta de que ese patrón en realidad no habla explícitamente sobre cómo se crean las fábricas.

Espero que esto responda a su pregunta.

Cuestiones relacionadas