El patrón de fábrica (o al menos el uso de FactoryFactory..
) es el blanco de muchos chistes, como aquí .
Además de tener nombres detallados y "creativos" como RequestProcessorFactoryFactory.RequestProcessorFactory , ¿hay algo fundamentalmente incorrecto con el patrón de fábrica si tiene que programar en Java / C ++ y hay un caso de uso para Abstract_factory_pattern ?
¿Cómo podría otro lenguaje popular (por ejemplo, Ruby o Scala ) evitar tener que usarlo mientras se maneja una complejidad similar?
La razón por la que pregunto es que veo principalmente las críticas a las fábricas mencionadas en el contexto del ecosistema Java / Java EE , pero nunca explican cómo otros lenguajes / marcos los resuelven.
java
design-patterns
senseiwu
fuente
fuente
Respuestas:
Su pregunta está etiquetada con "Java", no sorprende que se pregunte por qué se está burlando del patrón Factory: Java en sí viene con un abuso bien empaquetado de ese patrón.
Por ejemplo, intente cargar un documento XML desde un archivo y ejecute una consulta XPath en él. Necesita algo como 10 líneas de código solo para configurar las fábricas y constructores:
Me pregunto si los chicos que diseñaron esta API alguna vez trabajaron como desarrolladores o simplemente leyeron libros y arrojaron cosas. Entiendo que simplemente no querían escribir un analizador y dejaron la tarea a otros, pero aún así es una implementación fea.
Como se pregunta cuál es la alternativa, aquí está cargando el archivo XML en C #:
Sospecho que los desarrolladores de Java recién nacidos ven la locura de Factory y piensan que está bien hacerlo, si los genios que crearon Java los han usado tanto.
Factory y cualquier otro patrón son herramientas, cada una adecuada para un trabajo en particular. Si los aplica a trabajos que no son adecuados para usted, seguramente tendrá un código feo.
fuente
XmlDocument xml = new XmlDocument(); xml.Load("c:\\employees.xml"); XmlNodeList nodes = xml.SelectNodes(expression);
(En general, LINQ to XML es mucho más fácil de usar, aunque principalmente en otras áreas). Y aquí hay un artículo de KB Encontré, con un método recomendado por MS: support.microsoft.com/kb/308333Como a menudo, las personas no entienden lo que está sucediendo (y eso incluye muchas de las risas).
No es el patrón de fábrica per se lo que es malo tanto como la forma en que muchas personas (tal vez incluso la mayoría) lo usan.
Y eso sin duda proviene de la forma en que se enseña la programación (y los patrones). A los alumnos (a menudo llamándose a sí mismos "estudiantes") se les dice que "creen X usando el patrón Y" y después de algunas iteraciones de eso piensan que esa es la forma de abordar cualquier problema de programación.
Entonces comienzan a aplicar un patrón específico que les gusta en la escuela contra cualquier cosa, sea apropiado o no.
Y eso incluye a profesores universitarios que escriben libros sobre diseño de software, lamentablemente.
La culminación de esto fue un sistema que tuve el disgusto de tener que mantener creado por uno de ellos (el hombre incluso tenía varios libros sobre diseño orientado a objetos para su nombre, y un puesto de profesor en el departamento de informática de una universidad importante )
Se basó en un patrón de 3 niveles, con cada nivel en sí un sistema de 3 niveles (tiene que desacoplar ...). En la interfaz entre cada conjunto de niveles, en ambos lados, había una fábrica para producir los objetos para transferir datos al otro nivel, y una fábrica para producir el objeto para traducir el objeto recibido a uno que pertenece a la capa receptora.
Para cada fábrica había una fábrica abstracta (quién sabe, la fábrica podría tener que cambiar y luego no querrá que cambie el código de llamada ...).
Y todo ese desastre fue, por supuesto, completamente indocumentado.
El sistema tenía una base de datos normalizada a la 5ta forma normal (no es broma).
Un sistema que era esencialmente poco más que una libreta de direcciones que podía usarse para registrar y rastrear documentos entrantes y salientes, tenía una base de código de 100 MB en C ++ y más de 50 tablas de bases de datos. La impresión de 500 cartas formales tomaría hasta 72 horas con una impresora conectada directamente a la computadora que ejecuta el software.
Es por eso que las personas se burlan de los patrones, y específicamente las personas que se concentran de manera decidida en un solo patrón específico.
fuente
Las fábricas tienen muchas ventajas que permiten diseños de aplicaciones elegantes en algunas situaciones. Una es que puede establecer las propiedades de los objetos que luego desea crear en un lugar creando una fábrica, y luego entregar esa fábrica. Pero a menudo no necesitas hacer eso. En ese caso, usar una Fábrica simplemente agrega complejidad adicional sin realmente darle nada a cambio. Tomemos esta fábrica, por ejemplo:
Una alternativa al patrón Factory es el patrón Builder muy similar. La principal diferencia es que las propiedades de los objetos creados por una Fábrica se establecen cuando se inicializa la Fábrica, mientras que un Generador se inicializa con un estado predeterminado y todas las propiedades se establecen después.
Pero cuando la sobre ingeniería es su problema, reemplazar una Fábrica con un Constructor probablemente no sea una gran mejora.
El reemplazo más simple para cualquiera de los patrones es, por supuesto, crear instancias de objetos con un constructor simple con el
new
operador:Sin embargo, los constructores tienen un inconveniente crucial en la mayoría de los lenguajes orientados a objetos: deben devolver un objeto de esa clase exacta y no pueden devolver un subtipo.
Cuando necesite elegir el subtipo en tiempo de ejecución pero no desee recurrir a la creación de una clase Builder o Factory completamente nueva para eso, puede utilizar un método factory en su lugar. Este es un método estático de una clase que devuelve una nueva instancia de esa clase o una de sus subclases. Una Fábrica que no mantiene ningún estado interno a menudo se puede reemplazar con un método de fábrica de este tipo:
Una nueva característica en Java 8 son las referencias de métodos que le permiten pasar métodos, tal como lo haría con una fábrica sin estado. Convenientemente, cualquier cosa que acepte una referencia de método también acepta cualquier objeto que implemente la misma interfaz funcional, que también puede ser una Fábrica completa con estado interno, por lo que puede introducir fácilmente fábricas más tarde, cuando vea una razón para hacerlo.
fuente
foo = new Bar(23);
ser equivalente afoo = Bar._createInstance(23);
. Un objeto debería poder consultar de manera confiable su propio tipo utilizando ungetRealType()
método privado , pero los objetos deberían poder designar un supertipo para ser devuelto por llamadas externasgetType()
. El código externo no debería importar si una llamada anew String("A")
realmente devuelve una instancia deString
[en lugar de, por ejemplo, una instancia deSingleCharacterString
].draw(OutputStream out)
pero generan html ligeramente diferentes, la fábrica de métodos estáticos crea la clase adecuada para la situación y luego la persona que llama puede usar el método de dibujo.[[SomeClass alloc] init]
. Es posible devolver una instancia de clase completamente diferente u otro objeto (como un valor en caché)Las fábricas de uno u otro tipo se encuentran en prácticamente cualquier lenguaje orientado a objetos en circunstancias apropiadas. A veces, simplemente necesita una forma de seleccionar qué tipo de objeto crear basándose en un parámetro simple como una cadena.
Algunas personas lo llevan demasiado lejos e intentan diseñar su código para nunca tener que llamar a un constructor, excepto dentro de una fábrica. Las cosas comienzan a ponerse ridículas cuando tienes fábricas de fábrica.
Lo que me sorprendió cuando aprendí Scala, y no conozco a Ruby, pero creo que es de la misma manera, es que el lenguaje es lo suficientemente expresivo como para que los programadores no siempre estén tratando de llevar el trabajo de "plomería" a los archivos de configuración externos. . En lugar de sentirse tentado a crear fábricas de fábrica para conectar sus clases en diferentes configuraciones, en Scala utiliza objetos con rasgos mezclados. También es relativamente fácil crear DSLs simples en lenguaje para tareas que a menudo están sobredimensionadas en Java.
Además, como han señalado otros comentarios y respuestas, los cierres y las funciones de primera clase evitan la necesidad de muchos patrones. Por esa razón, creo que muchos de los antipatrones comenzarán a desaparecer a medida que C ++ 11 y Java 8 obtengan una adopción generalizada.
fuente
En general, existe la tendencia de que los programas de Java están terriblemente sobre-diseñados [cita requerida]. Tener muchas fábricas es uno de los síntomas más comunes de la sobre ingeniería; Por eso la gente se burla de ellos.
En particular, el problema que Java tiene con las fábricas es que en Java a) los constructores no son funciones yb) las funciones no son ciudadanos de primera clase.
Imagina que pudieras escribir algo como esto (deja que
Function
sea una interfaz bien conocida del JRE )Ver, no hay interfaces de fábrica o clases. Muchos lenguajes dinámicos tienen funciones de primera clase. Por desgracia, esto no es posible con Java 7 o anterior (implementar el mismo con las fábricas se deja como un ejercicio para el lector).
Por lo tanto, la alternativa no es tanto "usar un patrón diferente", sino más bien "usar un lenguaje con un mejor modelo de objeto" o "no sobre-diseñar problemas simples".
fuente