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 gestionados 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 activar este requisito en su cabeza, Windows Communication Foundation (WCF) tiene una clase ChannelFactory que define el siguiente método de fábrica estática:
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 nos fijamos en el reflector en el desmontaje de clase (Sistema. ServiceModel assembly & System.ServiceModel.Channels namespace), notará que "new()" no se usa como restricción.
Eso es porque el método utiliza CreateChannel typeof (TChannel) 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 de varios niveles más profundos como se está pasando la clase Tipo hacia abajo hasta el siguiente método se llama finalmente:
RemotingServices.CreateTransparentProxy(this, classToProxy, stub, stubData);
es extremadamente complicado, pero es la fábrica más complicada que he visto. 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.
El objetivo de una fábrica es separar la creación de objetos del cliente, y como tal, no hay nada de malo en una relación 1: 1 entre las clases concretas y las clases abstractas en un patrón de fábrica. – devlord
@lorddev Sí, pero YAGNI. Cuando realmente lo necesita, puede usar el patrón de fábrica. – inf3rno