使用工厂而不是构造函数创建对象的阈值是多少?
利弊
更新:我在我的项目中应用了Domain Driven Design的工厂模式。创建工厂背后的原因之一是减少域模型中的噪声。
由于
答案 0 :(得分:13)
如果我有一个抽象基类(或接口),我使用工厂,以及几个具体的派生类,并且有一些逻辑,根据这些逻辑创建一个具体类。我在工厂实现了这个逻辑。
答案 1 :(得分:5)
工厂最明显的情况是在运行时选择实现接口的特定类,例如,从配置文件中选择。我没有大量使用工厂,但是当我希望两个对象高度分离时,我更有可能使用工厂来获取另一个工具。
答案 2 :(得分:3)
与此主题相关的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;
}
如果在类反汇编(System.ServiceModel assembly&amp; System.ServiceModel.Channels命名空间)中查看Reflector,您会注意到“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类。
总之,工厂是针对具有很多复杂性或需要从动态类型构造中受益的对象。
答案 3 :(得分:2)
我不确定你是如何选择门槛的......
如果您不想从构造中抽象出对象的使用者,那么工厂是合适的。可能与此相关的实例:
查看Book of Four(Gamma等人)模式书并详细查看工厂模式,了解何时使用此模式的更多信息。
答案 4 :(得分:1)
我喜欢将构造函数的数量保持在合理的低水平;超过两三个,我质疑对象的结构是如何设计的。
如果引入其他构造函数来支持设置各种可选属性,我喜欢使用Builder,如 Effective Java 中所述(Joshua Bloch,2nd ed 。)
答案 5 :(得分:1)
这是一个激进的想法(我不是在提倡它,但我认为这不会有害):
始终使用工厂方法!
工厂方法更灵活,例如,它们可以缓存结果或返回子类。
所以,而不是:
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();
您现在可以更改“构造函数”逻辑以返回子类或缓存实例,并且所有调用者都不会受到影响。您现在可以控制“构造函数”的返回值。
答案 6 :(得分:0)
我试着在这些之间进行衡量。我认为你应该在以下时间使用工厂:
对于工厂,在这种情况下,您可以为要返回的对象状态指定正确的名称。
答案 7 :(得分:0)
当决定实例化哪个具体类不是由客户端决定时,请使用工厂。例如那里有几个“家庭”的物品,可以选择在其他地方使用哪个家庭。
答案 8 :(得分:0)
我认为你混淆了Builder模式和Factory模式。我建议只使用构造函数并完成它。听起来好像(没有看到代码)你过度思考或过度分析你的代码。