2009-01-28 40 views
11

使用工厂代替构造函数创建对象的阈值是什么?使用工厂而不是构造函数创建对象的阈值是什么?

  1. 您总是使用工厂。
  2. 只有在除检查空值之外还有不变检查时,才使用工厂。
  3. 你总是使用构造函数
  4. 你很少使用工厂......这些情况是什么?

利弊

更新:我从领域驱动设计在我的项目应用工厂模式。而创建工厂背后的原因之一就是减少领域模型中的噪音。

谢谢

回答

1

我喜欢把构造函数的数量保持在一个合理的低水平;超过两个或三个,我质疑物体的结构是如何设计的。

在额外的构造函数被引入以支持设定各种可选的属性的情况下,我喜欢用一个Builder,如在Effective Java描述(书布洛赫,第2版)

0

我尝试那些之间测量。我认为你应该在下列情况下使用工厂:

  1. 高参数。
  2. 可选参数。 (两者都使用内部类生成器模式)
  3. 由于相同的参数类型但不同的数据,您将不得不更改参数的顺序以实现其他操作。
  4. 你需要一个单独的类(用枚举做得更好)

设有工厂,在这种情况下,你可以在对象的状态给出一个合适的名字被返回。

2

我不清楚自己是如何选择你的门槛......

工厂是适当的,如果你不想抽象从施工对象的消费者。这可能是相关的实例:

  • 您可能希望在运行时分出实现。通常这与使用接口而不是具体类相结合。 Java中的一个例子就是如何从Java中的DocumentBuilder中获取Document对象。
  • 您可能想要限制对象的实例数量。考虑使用有限数量的线程对象构建一个池,而不是一直创建新的线程,而不是始终创建新线程

查看四本书(Gamma et。al。)模式书并详细查看工厂模式有关何时使用此模式的更多信息。

13

如果我有一个抽象基类(或一个接口)和几个具体的派生类,并且根据创建哪一个具体类,我使用了一个工厂。我在工厂实施这个逻辑。

+3

工厂的要点是将对象创建与客户端分开,因此,具体类与工厂模式中的抽象类之间的1:1比例没有任何问题。 – devlord 2009-02-07 01:54:07

5

工厂最明显的例子就是在运行时(例如从配置文件中)选择实现接口的特定类。我不大量使用工厂,但是当我想要两个对象高度分离时,我更可能使用工厂来获得另一个对象的实例。

0

当决定要实例化哪个具体类不是客户端时,使用工厂。例如哪里有几个“家庭”的对象,哪个家庭的选择是在别处制作的。

3

有关与此主题相关的C#的一些有趣之处在于,在类定义中指定的泛型类型上的new()约束强制通用容器类型处理的类型实现无参数构造函数。只有在想要创建类型T的实例时才需要new()约束,如类GenericType<T>中的类型。在我看来,这明显是支持阶​​级工厂,特别是生产普通类型的工厂。

要打开它的头这一要求,Windows通讯基础(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; 
} 

如果在反光的类反汇编看(系统。 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; 
} 

您可以按照委托链深几个级别与类型类被传递直到最后调用下面的方法:

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

这是非常复杂的,但它是我见过的最复杂的工厂。有趣的是,所有的诡计最终都由WCF从System.Runtime.Remoting.Proxies命名空间创建了一个RealProxy类。

总而言之,工厂是针对具有很多复杂性或需要从动态类型构造中受益的对象。

0

我觉得你很困惑Builder模式和Factory模式。我会建议只使用构造函数并完成它。这听起来像是(没有看到代码),你正在过度使用或过度使用代码。

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(); 

您现在可以更改“构造函数”逻辑以返回子类或缓存实例,并且所有呼叫者都不受影响。你现在控制你的“构造函数”的返回值。

相关问题