patron method ejemplo design design-patterns domain-driven-design factory

design - method - ¿Cuál es su umbral para usar fábrica en lugar de un constructor para crear un objeto?



factory method (9)

¿Cuál es su umbral para usar fábrica en lugar de un constructor para crear un objeto?

  1. Siempre usas fábrica
  2. Usas fábricas solo si tienes cheques invariables además de buscar nulos.
  3. Siempre usas constructores
  4. Raramente usas fábricas ... ¿qué son esos casos?

pros y contras

Actualización: estoy aplicando un patrón de fábrica de Domain Driven Design en mi proyecto. Y una de las razones detrás de la creación de fábricas es reducir el ruido en el modelo de dominio.

Gracias


El caso más obvio para una fábrica es cuando la clase específica que implementa una interfaz se elegirá en tiempo de ejecución, por ejemplo, desde un archivo de configuración. No hago un uso intensivo de las fábricas, pero cuando quiero que dos objetos estén muy desacoplados, es más probable que use una fábrica para obtener una instancia de la otra.


Intento medir entre esos. Creo que deberías usar fábricas cuando:

  1. Alto número de param.
  2. Param opcional (Ambos usan el patrón Builder de clase interna)
  3. Deberá cambiar el orden de los parámetros para poder realizar otra acción, debido a los mismos tipos de parámetros pero diferentes datos.
  4. Necesitas una clase singleton (mejor hecho con enum)

Con las fábricas, en este caso, puede dar un nombre propio al estado del objeto que se devuelve.


Me gusta mantener el número de constructores a un nivel bajo razonable; más de dos o tres, y me pregunto qué tan bien está diseñada la construcción del objeto.

En los casos en que se introducen constructores adicionales para admitir la configuración de varios atributos opcionales, me gusta usar un generador , como se describe en Java efectivo (Joshua Bloch, 2da ed.)


No estoy exactamente seguro de cómo elegiste tus umbrales ...

Las fábricas son apropiadas si no desea abstraer al consumidor del objeto de la construcción. Instancias donde esto puede ser pertinente:

  • Es posible que desee subcontratar la implementación en tiempo de ejecución. A menudo, esto se combina con el uso de interfaces en lugar de clases concretas. Un ejemplo en Java sería cómo obtienes un objeto de documento desde un DocumentBuilder en Java.
  • Es posible que desee limitar el número de instancias de un objeto. Piense en construir un Pool con un número limitado de objetos de subprocesos en lugar de solo crear nuevos todo el tiempo

Consulte el libro de patrones del Libro de los Cuatro (Gamma et al.) Y observe el patrón de fábrica en detalle para obtener más información sobre cuándo usar este patrón.


Use una fábrica cuando la decisión de qué clase concreta instanciar no corresponde al cliente. por ejemplo, donde hay varias "familias" de objetos y la elección de qué familia usar se hace en otra parte.


Utilizo una fábrica si tengo una clase base abstracta (o una interfaz) y varias clases derivadas concretas, y existe cierta lógica según la cual se crea una de las clases concretas. Implemento esa lógica en la fábrica.


Algo interesante acerca de C # que se relaciona con este tema, es que la nueva () restricción en los tipos genéricos que se especifican en una definición de clase obliga a los tipos manejados por el tipo de contenedor genérico a implementar un constructor sin parámetros. La restricción new () solo es necesaria cuando se pretende crear una instancia de tipo T, como en GenericType<T> , dentro de la clase. Me parece que esto es explícitamente en apoyo de las fábricas de clase, especialmente las fábricas que producen tipos genéricos.

Para poner este requisito en su punto crítico, Windows Communication Foundation (WCF) tiene una clase ChannelFactory que define el siguiente método de fábrica estático:

public static TChannel CreateChannel(Binding binding, EndpointAddress endpointAddress, Uri via) { ChannelFactory<TChannel> factory = new ChannelFactory<TChannel>(binding); if (factory.HasDuplexOperations()) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxInvalidStaticOverloadCalledForDuplexChannelFactory1", new object[] { factory.channelType.Name }))); } TChannel channel = factory.CreateChannel(endpointAddress, via); ChannelFactory<TChannel>.SetFactoryToAutoClose(channel); return channel; }

Si mira en Reflector en el desmontaje de clase (System.ServiceModel assembly & System.ServiceModel.Channels namespace), notará que "new ()" no se usa como restricción.

Esto se debe a que el método CreateChannel utiliza typeof (TChannel) para delegar la creación del objeto más abajo en la cadena ...

public virtual TChannel CreateChannel(EndpointAddress address, Uri via) { TChannel local; bool traceOpenAndClose = base.TraceOpenAndClose; try { using (ServiceModelActivity activity = (DiagnosticUtility.ShouldUseActivity && base.TraceOpenAndClose) ? ServiceModelActivity.CreateBoundedActivity() : null) { if (DiagnosticUtility.ShouldUseActivity) { ServiceModelActivity.Start(activity, this.OpenActivityName, this.OpenActivityType); base.TraceOpenAndClose = false; } if (address == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("address"); } if (base.HasDuplexOperations()) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxCreateNonDuplexChannel1", new object[] { base.Endpoint.Contract.Name }))); } base.EnsureOpened(); local = (TChannel) this.ServiceChannelFactory.CreateChannel(typeof(TChannel), address, via); } } finally { base.TraceOpenAndClose = traceOpenAndClose; } return local; }

Puede seguir la cadena de delegación varios niveles más profundos a medida que la clase Type se transmite hacia abajo hasta que finalmente se llame al siguiente método:

RemotingServices.CreateTransparentProxy(this, classToProxy, stub, stubData);

Es extremadamente intrincado, pero es la fábrica más complicada que he visto en mi vida. Curiosamente, todas las maquinaciones terminan con WCF creando una clase RealProxy desde el espacio de nombres System.Runtime.Remoting.Proxies.

En conclusión, las fábricas son para objetos que tienen mucha complejidad o necesitan beneficiarse de la construcción de tipo dinámico.


Creo que estás confundiendo el patrón del Constructor y el patrón de Fábrica. Sugeriría simplemente usar constructores y terminar con eso. Parece que (sin ver el código) estás pensando demasiado o analizando en exceso tu código un poco.


Aquí hay un pensamiento radical (no lo defiendo realmente, pero no creo que lo perjudique):

¡Siempre use los métodos de fábrica!

Los métodos de fábrica son más flexibles, por ejemplo, pueden almacenar en caché los resultados o devolver clases secundarias.

Entonces, en lugar de:

class SomeClass { public SomeClass(/*parameters*/) { /*...*/ } }

Siempre usa:

class SomeClass { protected SomeClass(/*parameters*/) { /*...*/ } public static SomeClass New(/*parameters*/) { return new SomeClass(/*parameters*/); } }

El código de la persona que llama cambia de:

SomeClass sc = new SomeClass();

A:

SomeClass sc = SomeClass.New();

Ahora puede cambiar su lógica de "constructor" para devolver subclases o instancias en caché, y todas las personas que llaman no se verán afectadas. Ahora controlas el valor de retorno de tus "constructores".