您使用工厂而不是构造函数来创建对象的阈值是多少?
- 你总是使用工厂。
- 仅当您有除检查空值之外的不变检查时,您才使用工厂。
- 你总是使用构造函数
- 你很少使用工厂......那些情况是什么?
利弊
更新:我在我的项目中应用域驱动设计的工厂模式。创建工厂的原因之一是减少领域模型中的噪音。
谢谢
您使用工厂而不是构造函数来创建对象的阈值是多少?
利弊
更新:我在我的项目中应用域驱动设计的工厂模式。创建工厂的原因之一是减少领域模型中的噪音。
谢谢
如果我有一个抽象基类(或接口)和几个具体的派生类,我会使用一个工厂,并且有一些逻辑根据哪个具体类来创建。我在工厂中实现了这个逻辑。
工厂最明显的情况是在运行时选择实现接口的特定类,例如从配置文件中选择。我没有大量使用工厂,但是当我希望两个对象高度解耦时,我更有可能使用工厂来获取另一个的实例。
与此主题相关的 C# 的一些有趣之处在于,对类定义中指定的泛型类型的 new() 约束强制由泛型容器类型处理的类型实现无参数构造函数。仅当打算在GenericType<T>
类中创建类型 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 程序集和 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 类。
总之,工厂适用于具有很多复杂性或需要从动态类型构造中受益的对象。
我不确定您是如何选择阈值的...
如果您不想从构造中抽象出对象的使用者,工厂是合适的。可能与此相关的实例:
查看 Book of Four (Gamma et. al.) 模式书并详细查看工厂模式以获取有关何时使用此模式的更多信息。
这是一个激进的想法(我并不是真的提倡它,但我认为它不会有害):
始终使用工厂方法!
工厂方法更灵活,例如,它们可以缓存结果或返回子类。
所以,而不是:
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();
您现在可以更改“构造函数”逻辑以返回子类或缓存实例,并且所有调用者都不会受到影响。您现在可以控制“构造函数”的返回值。
我喜欢将构造函数的数量保持在合理的低水平;超过两三个,我质疑这个物体的结构设计得有多好。
在引入其他构造函数以支持设置各种可选属性的情况下,我喜欢使用Builder,如Effective Java(Joshua Bloch,第 2 版)中所述。
当实例化哪个具体类的决定不取决于客户端时,请使用工厂。例如,当有多个对象“族”时,选择使用哪个族是在别处进行的。
我尝试在这些之间进行衡量。我认为你应该在以下情况下使用工厂:
对于工厂,在这种情况下,您可以为返回的对象状态指定一个正确的名称。
I think you are confusing the Builder pattern and the Factory pattern. I would suggest just using constructors and being done with it. It sounds like (without seeing the code) you're overthinking or overanalysing your code a bit.