【问题标题】:A static factory method on a generic or a non-generic class?泛型或非泛型类的静态工厂方法?
【发布时间】:2013-05-21 09:26:27
【问题描述】:

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

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

  1. 静态非泛型原厂方法泛型 MyClass<T>:

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

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

【问题讨论】:

标签: c# .net design-patterns factory factory-pattern


【解决方案1】:

乍一看,您的问题的正确答案似乎是#1。这是因为你的班级是MyClass&lt;T&gt;,因此工厂也应该是T-specific。但不仅仅是这个简单的答案。

在继续之前,我要添加第三种可能性:非静态工厂类。依赖于工厂的对象将具有一个公共属性,通过该属性它接收工厂对象。如果没有分配其他实例,则该属性的 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&lt;T&gt;,然后工厂也应该使用泛型参数:Factory&lt;T&gt;。此解决方案优于通用工厂上的通用方法,只是因为创建实例可能是T-specific。使用通用工厂的解决方案允许您这样做:

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

通过这种方式,您可以覆盖现有工厂类的行为,并有另一种方法来生成专用于字符串的实例。这很重要,因为处理字符串通常与处理 int 或 double 等原始类型有很大不同。有机会使工厂专业化可能是有益的。但是现在您明白了为什么拥有静态工厂可能是个坏主意 - 静态无法扩展。

【讨论】:

  • 许多有测试单元经验的有经验的开发人员都知道这两个选项都不好:)。恕我直言,构造函数注入比惰性获取更好,因为它更容易模拟和防止magic dependency。 +1 顺便说一句。
  • @Fendy - 关于构造函数,你是对的。我遵循的一般规则是对强制参数使用构造函数注入,对可选参数使用属性注入。 Lazy get 经常被滥用。我仅将其用作属性覆盖的模式。在上面的示例中,属性具有通常不应该更改的默认实现。只有偶尔(例如在单元测试中)你会用不同的实现来改变它。诀窍在于这个问题:更改属性值会破坏代码吗? YES 表示您对其进行硬编码; NO 表示 IoC 容器是正确的方法。
  • 如果changing a property value going to break the code 表示您需要修复实现,而不是硬编码默认值。我认为Lazy 属性的缺点是,如果需要更改它(DefaultFactory),那么你必须在每个地方都做。别担心,它可能不适用于这种(你的)情况,但可能会发生在其他情况下。虽然代码滥用很容易
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 2021-07-26
    • 1970-01-01
    • 2011-01-19
    • 2014-01-12
    • 2011-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    相关资源
    最近更新 更多