你在什么情况下会使用工厂方法而不是构造函数来创建对象?
- 始终使用工厂方法。
- 只有在存在除检查null之外的不变式检查时才使用工厂方法。
- 始终使用构造函数。
- 很少使用工厂方法...那些情况是什么?
优缺点
更新:我正在我的项目中应用领域驱动设计中的工厂模式。创建工厂的原因之一是减少领域模型中的噪音。
谢谢
你在什么情况下会使用工厂方法而不是构造函数来创建对象?
优缺点
更新:我正在我的项目中应用领域驱动设计中的工厂模式。创建工厂的原因之一是减少领域模型中的噪音。
谢谢
如果我有一个抽象基类(或接口)和几个具体派生类,并且存在某种逻辑来创建其中一个具体类,则我会使用工厂模式。 我在工厂中实现该逻辑。
当实现某个接口的具体类需要在运行时选择时(例如从配置文件中选择),使用工厂是最明显的情况。我并不经常使用工厂,但是当我希望两个对象高度解耦时,我更倾向于使用工厂来获取其中一个对象的实例。
关于与这个主题相关的C#有趣的事情是,类定义中指定的泛型类型上的new()约束强制由泛型容器类型处理的类型实现一个无参数构造函数。只有在想要在类内创建T类型的实例(如GenericType<T>
)时才需要new()约束。我认为这明确支持类工厂,特别是生成泛型类型的工厂。
为了颠覆这个要求,Windows Communication Foundation (WCF)有一个ChannelFactory类,定义了以下静态工厂方法:
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;
}
如果你在Reflector中查看类反汇编(System.ServiceModel程序集和System.ServiceModel.Channels命名空间),你会注意到“new()”没有被用作约束条件。
这是因为CreateChannel方法使用typeof(TChannel)将对象创建委托给链条下方...
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;
}
当Type类被传递下去并最终调用以下方法时,您可以跟随委托链更深几层:
RemotingServices.CreateTransparentProxy(this, classToProxy, stub, stubData);
这是一个非常复杂的工厂,但它是我见过最复杂的工厂。有趣的是,所有的机械构造最终都会通过WCF从System.Runtime.Remoting.Proxies命名空间创建一个RealProxy类。
总之,工厂适用于具有很多复杂性或需要受益于动态类型构建的对象。
我喜欢保持构造函数的数量不太多;超过两到三个,我会质疑对象的构建是否被设计良好。
在需要引入额外的构造函数以支持设置各种可选属性的情况下,我喜欢使用Builder,如在Effective Java(Joshua Bloch,第2版)中所述。
这里有一个激进的想法(我并不是真正提倡它,但我认为它不会有害):
始终使用工厂方法!
工厂方法更加灵活,例如,它们可以缓存结果或返回子类。
因此,不要这样写:
class SomeClass {
public SomeClass(/*parameters*/) { /*...*/ }
}
始终使用:
class SomeClass {
protected SomeClass(/*parameters*/) { /*...*/ }
public static SomeClass New(/*parameters*/) {
return new SomeClass(/*parameters*/);
}
}
调用者代码从以下内容更改:
SomeClass sc = new SomeClass();
致:
SomeClass sc = SomeClass.New();
现在,您可以更改“构造函数”逻辑以返回子类或缓存实例,而不会影响所有调用者。您现在控制“构造函数”的返回值。
我试图在它们之间进行衡量。我认为当以下情况时,您应该使用工厂模式:
在这种情况下,使用工厂模式,您可以为返回的对象状态提供适当的名称。
我认为你把生成器模式和工厂模式混淆了。我建议只使用构造函数并完成它。听起来(没有看到代码)你可能有点过于深思熟虑或者过度分析代码。