¿Por qué este ShapeFactory utiliza declaraciones condicionales para determinar qué objeto instanciar? ¿No tenemos que modificar ShapeFactory si queremos agregar otras clases en el futuro? ¿Por qué esto no viola el principio abierto cerrado?
design
design-patterns
factory-method
factory
Armon Safai
fuente
fuente
Respuestas:
La sabiduría convencional orientada a objetos es evitar
if
enunciados y reemplazarlos con despacho dinámico de métodos anulados en subclases de una clase abstracta. Hasta aquí todo bien.Pero el objetivo del patrón de fábrica es liberarlo de tener que conocer las subclases individuales y trabajar solo con la superclase abstracta . La idea es que la fábrica sepa mejor que usted qué clase específica crear, y será mejor que trabaje solo con los métodos publicados por la superclase. Esto es a menudo cierto y un patrón valioso.
Por lo tanto, no hay forma de que escribir una clase de fábrica pueda renunciar a las
if
declaraciones. Cambiaría la carga de elegir una clase específica a la persona que llama, que es exactamente lo que se supone que debe evitar el patrón. No todos los principios son absolutos (de hecho, ningún principio es absoluto), y si usa este patrón, supondría que el beneficio es mayor que el beneficio de no usar unif
.fuente
if
s. Vea la respuesta de @ BЈовић para un ejemplo simple de cómo lograr esto. Voto negativoEl ejemplo probablemente usa una declaración condicional porque es la más simple. Una implementación más compleja podría usar un mapa o configuración o (si quieres ser realmente elegante) algún tipo de registro donde las clases puedan registrarse por sí mismas. Sin embargo, no hay nada de malo en usar un condicional si el número de clases es pequeño y cambia con poca frecuencia.
Extender el condicional para agregar soporte para una nueva subclase en el futuro sería, estrictamente hablando, una violación del principio abierto / cerrado. La solución "correcta" sería crear una nueva fábrica con la misma interfaz. Dicho esto, la adhesión al principio de O / C siempre debe compararse con otros principios de diseño como KISS y YAGNI.
Dicho esto, el código que se muestra es claramente un código de ejemplo que está diseñado para mostrar el concepto de fábrica y nada más. Por ejemplo, es realmente un mal estilo devolver nulo como lo hace el ejemplo, pero un manejo de errores más elaborado simplemente oscurecería el punto. El código de ejemplo no es un código de calidad de producción, ninguno no debería esperar que sea.
fuente
El patrón en sí mismo no viola el Principio Abierto / Cerrado (OCP). Sin embargo, violamos el OCP cuando usamos el patrón incorrectamente.
La respuesta simple a esta pregunta es la siguiente:
En el ejemplo proporcionado, su funcionalidad base admite tres formas: Círculo, Rectángulo y Cuadrado. Suponga que necesita admitir Triángulo, Pentágono y Hexágono en el futuro. Para hacer esto SIN violar OCP, debe crear una fábrica adicional para admitir sus nuevas formas (llamemos
AdvancedShapeFactory
) y luego usar AbstractFactory para decidir qué fábrica necesita crear para crear las formas que necesita.fuente
Si está hablando del patrón Abstract Factory, la toma de decisiones a menudo no está en la Factory en sí, sino en el código de la aplicación. Es ese código el que elige qué fábrica de concreto instanciar y pasar al código del cliente que utilizará los objetos producidos por la Fábrica. Vea el final del ejemplo de Java aquí: https://en.wikipedia.org/wiki/Abstract_factory_pattern
La toma de decisiones no necesariamente implica
if
declaraciones. Podría leer el tipo concreto de Factory de un archivo de configuración, derivarlo de una estructura de mapa, etc.fuente
Si piensa en Open-Close a nivel de clase con esta fábrica, está creando otra clase en su sistema Open-Close, por ejemplo, si tiene otra clase que toma una Forma y calcula el área (ejemplo típico), esta clase es OpenClose porque Puede calcular el área para nuevos tipos de formas sin modificación. Luego tiene otra clase que dibuja la forma, otra clase que toma N formas y devuelve la más grande y puede pensar en general que las otras clases en su sistema que tratan con formas son Open-Close (al menos sobre formas). Mirando el diseño, la fábrica permite que el resto del sistema sea Abierto-Cerrado y, por supuesto, la fábrica misma NO ES Abrir-Cerrar.
Por supuesto, también puede hacer que esta fábrica se abra-cierre, a través de algún tipo de carga dinámica y todo su sistema puede ser Abrir-Cerrar (puede agregar nuevas formas dejando caer un tarro en el classpath, por ejemplo). Debe evaluar si esta complejidad adicional vale la pena dependiendo del sistema que esté construyendo, no todos los sistemas necesitan características conectables y no todo el sistema debe estar completamente abierto-cerrado.
fuente
El principio abierto-cerrado, como el principio de sustitución de Liskov, se aplica a los árboles de clase, a las jerarquías de herencia. En su ejemplo, la clase de fábrica no está en el árbol genealógico de las clases que instancia, por lo que no puede violar estas reglas. Habría una violación si su GetShape (o más acertadamente, CreateShape) se implementara en la clase base Shape.
fuente
Todo depende de cómo lo implemente. Puede usar
std::map
para mantener punteros de función a funciones que crean objetos. Entonces no se viola el principio de apertura / cierre. O interruptor / caja.De todos modos, si no le gusta el patrón de fábrica, siempre puede usar la inyección de dependencia.
fuente