2013-05-21 204 views
2

我有一个通用类,我们称之为MyClass<T>,它需要一个工厂方法,以便从客户端代码抽象构造函数细节。泛型类或非泛型类的静态工厂方法?

这两个选项中的哪一个是正确的? (包括例如实例化代码)

  1. 静态非通用工厂上的原始通用MyClass<T>方法:

    MyClass<SomeType> instance = MyClass<SomeType>.CreateNew(); 
    
  2. 静态通用工厂方法上的专用, 非通用静态MyClass实现塔季翁:

    MyClass<SomeType> instance = MyClass.CreateNew<SomeType>(); 
    
+0

我认为这个问题是一个很好的人选[你最有争议的编程观点是什么?](http://stackoverflow.com/questions/406760/whats-your-most-controversial-programming-opinion),但只适用于C#语言 –

回答

1

在乍一看,貌似正确回答你的问题是#1。这是因为你的班级是MyClass<T>,因此工厂也应该是T特定的。但还有更多的东西比这个简单的答案。

在继续之前,我会添加第三种可能性:非静态工厂类。依赖于工厂的对象会拥有一个公共属性,通过它可以接收工厂对象。如果没有其他实例被分配,属性的Getter将实例化默认工厂。这允许以后依赖注入,并且还有助于编写依赖于他们自己的假工厂的单元测试。解决方案会是这个样子(忽略了片刻仿制药):

public class ISomeFactory { ... } 

public class DefaultSomeFactory: ISomeFactory { ... } 

public class ClientClass 
{ 
    public ISomeFactory FactoryOfSome // Right place for dependency injection 
    { 
     get 
     { 
      if (_fact == null) 
       _fact = new DefaultFactory(); 
      return _fact; 
     } 
     set { _fact = value; } 
    } 
    private ISomeFactory _fact; 
} 

现在,就像我说的,你们班去与通用参数MyClass<T>然后工厂应与泛型参数去还有:Factory<T>。这个解决方案比一般工厂的通用方法更好,只是因为创建一个实例可能是特定于T。与一般的工厂解决方案可以让你:

public class SpecialSomeFactory: DefaultSomeFactory<string> { ... } 

通过这种方式,可以覆盖现有的工厂类的行为,并以另一种方式产生的特殊字符串实例。这很重要,因为处理字符串通常与处理诸如int或double的基本类型大不相同。有机会专业化工厂可能是有益的。但是现在你明白为什么有一个静态工厂可能是一个坏主意 - 静态不能被扩展。

+1

许多有经验的测试单位经验的开发人员都知道这两个选项都不好:)。恕我直言,最好做构造函数注入而不是懒得到,因为它更容易模拟和防止'魔术依赖'。 +1 btw。 – Fendy

+0

@芬迪 - 你是对的构造函数。我遵循的一般规则是为必需参数使用构造函数注入,为可选参数使用属性注入。懒得到经常被滥用。我只用它作为财产重写的模式。在上面的例子中,属性具有一般不应该被改变的默认实现。只有一段时间(例如在单元测试中),您将使用不同的实现来更改它。诀窍是在这个问题:改变一个属性值会打破代码? YES意味着你对它进行硬编码; NO表示IoC容器是正确的方式。 –

+1

如果“更改属性值将破坏代码”意味着您需要修复实现,而不是硬编码默认值。我认为'Lazy'属性的缺点是,如果需要更改(DefaultFactory),那么你必须在每个地方都做。不要担心,它可能不适用于这个(你)的情况,但可以在其他情况下发生。代码滥用很容易 – Fendy

1

这两个示例本质上都是服务定位器模式的变体。有争议的是,这通常被认为是反模式,因为使用它的类的依赖关系对其消费者是不可见的。

使您的依赖更加明确的一种方法是采用类似于第一个示例的解决方案,但使CreateNew()成为实例方法,而不是静态方法。