2009-11-16 9 views
5

Mi comprensión de una fábrica es que encapsula la creación de instancias de clases concretas que todas heredan una clase o interfaz abstracta común. Esto permite que el cliente se desacople del proceso de determinar qué clase concreta crear, lo que a su vez significa que puede agregar o eliminar clases concretas de su programa sin tener que cambiar el código del cliente. Puede que tenga que cambiar la fábrica, pero la fábrica está "construida a propósito" y realmente solo tiene una razón para cambiar: se ha agregado/eliminado una clase concreta.¿Es confuso llamar a esta clase una "fábrica"?

He creado algunas clases que, de hecho, encapsulan la instanciación de objetos, pero por una razón diferente: los objetos son difíciles de crear. Por el momento, llamo a estas clases "fábricas", pero me preocupa que pueda ser un término inapropiado y que podría confundir a otros programadores que podrían ver mi código. Mis clases de "fábrica" ​​no deciden qué clase concreta crear, garantizan que una serie de objetos se instanciará en el orden correcto y que las clases correctas se pasarán a los constructores correctos cuando llame al new().

Por ejemplo, para un proyecto de MVVM en el que estoy trabajando, escribí una clase para asegurarme de que mi SetupView se instanciara correctamente. Se ve algo como esto:

public class SetupViewFactory 
{ 
    public SetupView CreateView(DatabaseModel databaseModel, SettingsModel settingsModel, ViewUtilities viewUtilities) 
    { 
     var setupViewModel = new SetupViewModel(databaseModel, settingsModel, viewUtilities); 
     var setupView = new SetupView(); 
     setupView.DataContext = setupViewModel; 
     return setupView; 
    } 
} 

Es confuso para llamar a esto una "fábrica"? No decide entre varias clases concretas posibles, y su tipo de devolución no es una interfaz o tipo abstracto, pero encapsula la instanciación de objetos.

Si no es una "fábrica", ¿qué es?


Editar

Varias personas han sugerido que este es en realidad el Builder.

La definición del Builder de dofactory es el siguiente:

independiente la construcción de un objeto complejo de su representación de manera que el mismo proceso de construcción pueden crear diferentes representaciones.

Esto también parece un poco exagerado. Lo que me molesta son las "diferentes representaciones". Mi propósito no es abstraer el proceso de construcción de una Vista (no es que esa no sea una meta digna). Simplemente trato de poner la lógica para crear una vista específica en un solo lugar, de modo que si alguno de los ingredientes o el proceso para crear esa vista cambian, solo tengo que cambiar esta clase. El patrón de construcción realmente parece decir: "Creemos un proceso general para crear Vistas, luego puede seguir el mismo proceso básico para cualquier Vista que cree". Bien, pero eso no es lo que estoy haciendo aquí.


Editar 2

Acabo de encontrar un ejemplo interesante en un Wikipedia article on Dependency Injection.

En "La dependencia inyectado de forma manual", que contiene la clase siguiente:

public class CarFactory { 

    public static Car buildCar() { 
     return new Car(new SimpleEngine()); 
    } 

} 

Esto es casi exactamente el uso que tengo (y no, no he escrito el artículo de wiki :)).

Curiosamente, este es el comentario siguiente este código:

En el código anterior, la fábrica tiene la responsabilidad de montar el coche, e inyecta el motor en el coche. Esto libera al automóvil de saber cómo crear un motor, aunque ahora el CarFactory tiene que saber sobre la construcción del motor. Uno podría crear una EngineFactory, pero eso simplemente crea dependencias entre las fábricas. Así que el problema persiste, pero al menos se ha cambiado a fábricas, o constructores objetos. [mi énfasis]

Así que, esto me dice que al menos no soy el único que pensó en crear una clase para ayudar con la inyección de material en otra clase, y no soy el único que intentó para nombrar a esta clase como una fábrica.

+2

No es nada quisquilloso, pero puede cambiar el nombre de su método a Create o CreateSetupView. – Mathias

+0

Si eso es todo lo que intentas lograr, no se trata realmente de ninguno de los patrones, solo actualiza todo en alguna clase de nivel superior. Es incorrecto llamarlo una fábrica sí. – Chap

+0

Suena como el patrón del constructor de instancias. –

Respuesta

4

Esto no suena muy diferente a mí que un constructor para una instancia de SetupView. Tal vez se eliminó demasiado contexto de código de su ejemplo, pero no veo por qué lo que tiene allí no puede simplemente escribirse como un constructor, y los argumentos pasan como args al constructor.

A juzgar estrictamente de patrones GoF, creo que pierde la marca de fábrica por dos razones:

  1. no hay familia de objetos/dependientes relacionadas
  2. la clase concreta es, de hecho, se especifica

Con respecto a Builder, creo que se pierde en el aspecto de la varianza de los productos.

Cuando enseño cursos de Diseño de patrones, les digo a los estudiantes que observen no solo la intención de un patrón cuando intentan determinar el "mejor ajuste", sino más bien observar la aplicabilidad y la estructura/participantes. El propósito puede ayudarlo a descartar las cosas, pero la aplicabilidad & estructura/participantes es lo que lo ayudará a su casa.

Si puede identificar qué parte de su diseño cumple las diversas funciones de los participantes en (Resumen) Fábrica o Constructor, entonces ha hecho un buen caso para usar esa nomenclatura.

+0

Gracias, @Chris, estoy de acuerdo contigo. Mi clase realmente no sigue ninguno de los patrones, pero para ser honesto, en realidad no fue intencionado. Lo que sí quiero saber es si secuestrar un esquema común de nomenclatura de clase de un patrón es algo malo si realmente no estoy implementando ese patrón. ¿Alguna idea sobre eso? Y también, por favor vea mi segunda edición de mi pregunta. – devuxer

+0

@Chris, también, consulte mi comentario sobre la respuesta de @Jeff Sternal para obtener una explicación sobre por qué no solo escribo un constructor para SetupView. – devuxer

+0

En la medida en que uno de los propósitos principales de los patrones en general es definir un lenguaje común, entonces, sí, creo que es engañoso llamarlo algo que no lo es, * especialmente * si está usando otros elementos del lenguaje de patrones en una forma más "verdadera". Por ejemplo, podemos usar la palabra "automóvil" en una conversación y nunca tener que especificar el número de ruedas, la existencia de un motor, puertas, tamaño, etc. porque ese término incorpora una comprensión común. Para mí, llamar a algo "coche" en nuestra conversación, cuando en realidad es un semirremolque es engañoso. –

1

GoF llaman "Builder"

+0

Por lo que yo sé, un Constructor necesita un Director y Producto –

+2

Director es el código del cliente, y el Producto es evidentemente un SetupView. –

1

creo, es una "fábrica". Cuando miro la declaración de clase, me alegra ver que se trata de una "fábrica" ​​y, además, es una "fábrica" ​​de objetos SetupView. Así que sé que esta Factory me dará instancias de SetupView concretas y construidas correctamente.

4

Se ve a mí como lo que tiene que hay más de un patrón Builder que un patrón de fábrica.

0

Podría llamarlo "asistente".

1

Una "fábrica" ​​es todo lo que encapsula la creación de instancias de objetos nuevos. Por qué, o qué son los objetos, no importa. El uso más común es el que usted describe, pero otros propósitos que no se ajustan a esa descripción también se pueden llamar Fábrica. La idea fundamental, (que no creo que el desarrollador más anal o quisquilloso pueda malinterpretar), es que la cosa crea nuevos objetos para usted ...

1

Esto me parece un poco extraño. No es una fábrica abstracta, pero tampoco encaja en el patrón del Constructor. Lo que tendría más sentido para mí es que en lugar de tener SetupViewFactory con el método CreateView, movería este método a la clase SetupView y lo convertiría en estático. Entonces usted tendría ...

public class SetupView 
{ 
    public static SetupView CreateView(DatabaseModel databaseModel, SettingsModel settingsModel, ViewUtilities viewUtilities) 
    { 
     var setupViewModel = new SetupViewModel(databaseModel, settingsModel, viewUtilities); 
     var setupView = new SetupView(); 
     setupView.DataContext = setupViewModel; 
     return setupView; 
    } 
} 

Ahora tiene lo que se conoce como la fábrica estática o un método de fábrica. Puede dar un paso más y privatizar los constructores de SetupView para que la única forma de obtener una instancia de SetupView sea llamar al método de fábrica.

En respuesta al comentario de OP:

Si hay tal necesidad de la separación que evitaría la creación de la SetupViewModel en cualquier lugar en esta parte del código. En su lugar, simplemente pase el SetupViewModel que desea asociar con su SetupView en lugar de las propiedades de los constituyentes para pasar al constructor de SetupViewModel. Entonces el código se convierte ...

public class SetupView 
{ 
    public static SetupView CreateView(SetupViewModel model) 
    { 
     var setupView = new SetupView(); { DataContext = model }; 
     return setupView; 
    } 
} 
+1

@ Jason que definitivamente lo llevaría al lado de la fábrica. A la inversa, podría dividir el CreateView en funcionalidades separadas y hacer que el paso final devuelva el SetupView, que se inclinaría hacia Builder. Creo que definitivamente podría ser en ambos sentidos. – Joseph

+0

Una idea interesante, pero con mi diseño actual, creo que hay una separación deseable entre SetupView y SetupViewModel. Me gustaría usar un ViewModel diferente con mi View, lo que significaría que podría simplemente crear otra fábrica (o editar la fábrica) en lugar de jugar con mi View. – devuxer

+0

@Jason, gracias por la adición a su respuesta, pero ahora estamos de vuelta al punto de partida :) El objetivo de lo que estoy tratando de hacer es automatizar y garantizar el proceso de creación de un ViewModel, creando una vista, configurando el DataContext y devolver una vista que está "lista para funcionar".Lo que has hecho aquí es mover parte de esta responsabilidad a la clase SetupView, lo cual está bien (quizás incluso sea bueno), pero ahora, cualquier clase que sea responsable de llamar a 'SetupView.CreateView()' todavía necesita un nombre. (Y tenga en cuenta que tengo otros ejemplos que son más complicados que este.) – devuxer

0

Me gustaría estar de acuerdo con Jason anterior. Para mí, es más como un patrón de generador pero si convertiste a SetupView en una interfaz, sería más como un patrón de fábrica. La clave del patrón Factory es dejar que el patrón Factory haga todo el trabajo para decidir qué devolver desde la llamada a la función. Entonces, creo que tendrías que tener un interruptor seleccionando entre varias opciones dados los parámetros de entrada.

1

¿Por qué no dos clases con constructores simples?

public class SetupViewModel { 
     public SetupViewModel(DatabaseModel databaseModel, SettingsModel settingsModel, ViewUtilities viewUtilities) { 
      this.DatabaseModel = databaseModel; 
      this.SettingsModel = settingsModel; 
      this.ViewUtilities = viewUtilities; 
     } 
} 

y

public class SetupView {   
     public SetupView(SetupViewModel model) {    
      this.DataContext = model; 
     } 
} 

De esta manera, las dos clases claramente indican lo que necesitan para ser construido.

+0

Gracias, Jeff. Eso es casi exactamente lo que ya tengo para 'SetupViewModel'. No tengo el 'SetupView' establecido su propio DataContext sobre todo porque esa no es la convención utilizada para el patrón MVVM. La idea es que se supone que 'View' debe ser generado por diseñadores/artistas usando, por ejemplo, Expression Blend, por lo que es mejor tener un código pequeño detrás del código. Además, puede conectar una nueva vista en cualquier momento que desee sin tener que agregar el código que establece DataContext. – devuxer

+0

¡Ah, lo tengo! En ese caso, esto parece completamente apropiado, aunque estoy de acuerdo con otros en que esto es muy cercano a ser un constructor. Si agrega un método virtual CreateSetupView (llamado en lugar de la nueva instrucción), estará allí, y eso podría ser útil. –

Cuestiones relacionadas