2010-04-23 14 views
8

Esto me ha molestado por un tiempo, y no tengo ninguna pista si esto es un mito.mito sobre el patrón de la fábrica

Parece que un patrón de fábrica puede aliviar el dolor de agregar una dependencia para una clase.

Por ejemplo, en un libro, que tiene algo como esto

Suponga que tiene una clase denominada Orden. Inicialmente no dependía de nada. Por lo tanto, no se molestó en usar una fábrica para crear objetos Order y simplemente utilizó plain new para crear instancias de los objetos. Sin embargo, ahora tiene un requisito de que el Pedido debe crearse en asociación con un Cliente. Hay millones de lugares que necesita cambiar para agregar este parámetro adicional. Si solo hubiera definido una fábrica para la clase de Orden, habría cumplido con el nuevo requisito sin el mismo dolor.

¿Cómo no es tan doloroso como agregar un parámetro extra al constructor? Quiero decir que todavía necesitarías dar un argumento extra para la fábrica y eso también es usado por millones de lugares, ¿verdad?

+0

Hay millones (si no miles de millones) de libros disponibles. No todos son correctos. No dé nada por sentado solo porque alguien lo escribió en un libro. – kazanaki

Respuesta

5

Si el usuario se conoce solo en ese momento, se crea el pedido, puede implementar una función getCurrentUser() que se llama de fábrica.
Si eso es posible, la función de fábrica obviamente gana. Si no, entonces no hay ganancia.

Si, en el pasado, no sabía que se necesitaría un cliente, probablemente tampoco podría saber si es posible implementar una función getCurrentUser(). Las posibilidades de que el método de fábrica sea rentable pueden no ser muy buenas, pero no siempre equivalen a 0.

+0

Creo que es exactamente lo que estoy buscando. – leiz

+1

exactamente. si necesita información nueva, su fábrica no lo ayudará. Si tiene o puede obtener la información que necesita, la fábrica ayuda a evitar los cambios en todas partes. –

1

Usted le dice a la fábrica sobre la nueva dependencia, y lo deja para que la agregue. La llamada de método a la fábrica no debe modificarse.

+0

Si tengo que decirle a la fábrica sobre la nueva dependencia, ¿cómo es esto diferente de usar el antiguo "nuevo" simple y agregar un argumento adicional? La nueva dependencia no es un objeto fijo. – leiz

+0

Usted le dice a la fábrica una vez, no en todas partes en el código donde llama a la fábrica para crear el objeto. –

2

No, porque la dependencia de la fábrica debe inyectarse a través del constructor de fábricas, y solo está construyendo la fábrica en un lugar, pero la pasa como dependencia de todo lo que necesita para crear un pedido. Las cosas que están recibiendo órdenes de fábrica todavía están pidiendo el mismo método, createOrder() o lo que sea, y para que el código no ha cambiado.

Las dependencias de todos deben ser conectados en un solo lugar, la composition root, y que deberían ser el único lugar que tiene que cambiar, añadir la nueva dependencia a la fábrica

+0

No lo entiendo del todo. Supongamos que quiero crear un objeto Order, depende de un objeto cliente, pero el cliente es conocido solo en el momento de crear el objeto Order. ¿Cómo se supone que configurará la fábrica en una etapa temprana? – leiz

+0

Esto no agrega una dependencia a la clase, ¿o sí? esto es agregar nueva información. Si necesita información nueva para poder crear su pedido, entonces deberá agregarla en todas partes. Pero si puede determinar al cliente a partir de la información existente, por ejemplo, si la clase de Orden tuvo acceso a una implementación ICustomerResolver, entonces, si hubiera utilizado una fábrica, podría inyectar ICustomerResolver en la fábrica y su Código de creación de pedido no se modificaría. Sin la fábrica, necesitaría inyectar ICustomerResolver en cada constructor de pedidos. –

+0

Lo siento, pero pensé que una nueva información era una dependencia. Y todos los diseños tenían que saber que habría un nuevo requisito del cliente. Es por eso que estoy diciendo que el libro es engañoso. – leiz

1

The factory pattern puede ayudar a aliviar el dolor de la adición una dependencia, porque una fábrica puede contener el estado y, de hecho, puede encapsular varias dependencias (por ejemplo, en lugar de proporcionar tres dependencias, todas necesarias para invocar el constructor de algún objeto, ahora solo proporciona un único objeto de fábrica; tres objetos que se deben proporcionar al constructor).

Para dar un ejemplo, comparar:

void DoIt(const DependencyA& a, const DependencyB& b) { 
    // NOTE: "x" is a contrived additional variable that we add here to 
    // justify why we didn't just pass DependencyC directly. 
    int x = ComputeX(); 
    std::unique_ptr<DependencyC> dependency_c(new DependencyC(a, b, x)); 
    dependency_c->DoStuff(); 
} 

Y:

void DoIt(const DependencyCFactory& factory) { 
    int x = ComputeX(); 
    std::unique_ptr<DependencyC> dependency_c(factory->Create(x)); 
    dependency_c->DoStuff(); 
} 

Tenga en cuenta que la segunda versión requiere un menor número de dependencias con el método "DoIt". Esto no quiere decir que esas dependencias no se necesitan en todo el programa (de hecho, el programa todavía hace uso de DependencyA y DependencyB en el implementaiton de la fábrica). Sin embargo, mediante la estructuración de esta manera, que la dependencia se puede aislar a sólo el código de fábrica, lo que mantiene otro código más simple, hace que sea más fácil cambiar las dependencias de DependencyC (ahora sólo la fábrica, en sí, necesita ser actualizado, no todos los lugares que ejemplifica DependencyC), e incluso puede tener ciertas ventajas de seguridad (por ejemplo, si DependencyA y DependencyB son sensibles, como contraseñas de bases de datos o claves API, limitar su uso a la fábrica reduce las posibilidades de mal manejo, en comparación con los casos donde donde sea que necesites usar el databse o la API, por ejemplo).

En el ejemplo dado en el libro, la razón por la que habría ayudado una fábrica para el Order es que habría reducido el número de lugares donde el constructor se usa directamente; solo el único lugar que creó la fábrica necesitaría modificarse para almacenar el Customer como un campo adicional de la fábrica; ninguno de los otros usos de la fábrica necesitaría ser modificado. En comparación, sin el uso de la fábrica, abundan los usos directos del constructor, y cada uno de ellos debe actualizarse para obtener de algún modo acceso al objeto Customer.

+0

Gracias por el código. Pero, para crear MyClassFactory2, necesito proporcionar p1 y p2. Si p1 y p2 solo se conocen en el momento en que necesito crear MyClass, ¿qué diferencia hay entre insertar un extra al constructor? – leiz

+1

@leiz, si los parámetros son una dependencia externa, todo lo que proporcione esa dependencia externa también debería ser capaz de proporcionar el objeto de fábrica. Si no, entonces tienes razón, no ayuda. –

3

El beneficio real de usar una fábrica es que es una fachada que oculta cómo se crea un objeto que cumple la función de orden. Para ser más exactos, Factory sabe que realmente está haciendo un FooBarOrder, y nada más tiene que cambiarse para pasar de hacer siempre un FooBarOrder a hacer un BarFooOrder en su lugar. (Si Java te permite interceptar new y crear una subclase, no habría necesidad de fábricas. Pero no es razonablemente justo, para ser justo, así que tienes que tenerlos. Sistemas de objetos que permiten la subclasificación de la clase de clases son más flexibles en este sentido.)

+0

Así entiendo también el patrón de fábrica. Pero la gente sigue diciendo que también es útil en el caso de agregar dependencia, y eso es algo que no entiendo. – leiz

+0

Originalmente tenía una orden, creada por su fábrica, implementando IOrder. Ahora quiere tener un CustomerOrder.Suponiendo que toda la información requerida para crear un CustomerOrder está disponible en la misma información necesaria para crear un pedido, o puede determinarse a partir de esa información o de forma estática, la fábrica ahora puede devolver un CustomerOrder sin ningún cambio en el código. Si la fábrica necesita una nueva dependencia para ayudarlo a obtener el CustomerObject necesario para crear el CustomerOrder, ese cambio solo tiene que pasar a la fábrica, no a cada lugar donde crea un pedido. –

Cuestiones relacionadas