【问题标题】:static factory methods vs factories静态工厂方法与工厂
【发布时间】:2011-05-03 14:58:19
【问题描述】:

我的类应该具有带有私有设置器的属性(或与之关联的私有字段和只读属性)。如果我在这些类中有静态工厂方法来创建实例,那也没关系。然而很多开发者写到“静态工厂方法是架构黑洞”,因为它不可能继承静态方法。

C# 没有友好的类,因此我不能使用工厂来做到这一点。

您如何看待使用静态工厂方法?

【问题讨论】:

  • 为什么不能在构造函数中传递值?

标签: .net design-patterns architecture factory-pattern


【解决方案1】:

默认情况下,我会通过将所需的参数传递给构造函数来创建实例。如果构造函数有很多参数,你要么需要parameter object,要么违反SRP。如果您有多种根据参数创建实例的选择,并且逻辑并不比静态工厂方法复杂,则可能是将创建逻辑保留在类中的最佳方式。

如果您有复杂的实例创建规则,这些规则取决于参数和其他因素,您可以使用工厂,也许是流利的工厂,它收集所有必需的参数并执行所需的逻辑,然后使用类公共构造函数来创建物体。

【讨论】:

  • 感谢您的回答,但是“如果您有多种选择根据参数创建实例”是什么意思?
  • 想象一下您需要实例化一个电子邮件发送类。可以有多个构造函数。一个接受远程地址、用户和密码的方法。一个需要一个文件夹。一个采用禁用电子邮件发送的 bool 参数的方法。现在,您有多种选择来创建实例,具体取决于用户提供的参数。使用工厂方法或流利的工厂来创建这个类使代码更具表现力。
【解决方案2】:

类的所有只读依赖项都应该由该类型的构造函数注入。这使代码更易于理解、调试,最重要的是,更易于测试。所以如果这是不可能的,那么真的应该考虑你的类层次结构。如果您仔细遵循此原则,您还可以使用依赖注入框架在运行时解决此依赖关系。

示例:

class Foo : IFoo
{
    private readonly IBar bar;
    private readonly IBaz baz;

    public Foo(IBar bar, IBaz baz)
    {
        this.bar = bar;
        this.baz = baz;
    }

    // Readonly properties for bar and baz, if needed.
} 

【讨论】:

    【解决方案3】:

    我不认为这种说法:

    C# 没有友好的类, 因此我不能使用工厂来做到这一点

    是真的。

    关键是不要在执行实现的类上创建静态工厂方法。你不能在这里逃避强耦合。

    您可能想研究依赖注入/反转。您不必担心创建工厂,而是通过 /code config 设置对象的创建方式; DI 框架为您提供工厂,并连接您指示需要的任何依赖项。

    【讨论】:

      【解决方案4】:

      我相信当人们说静态工厂方法“...... [是]一个架构黑洞”时,他们指的是扩展工厂方法是一团糟的问题。判断点是创建的类有多复杂。如果它们是重量级的,那么从长远来看,静态工厂方法可能会变得一团糟。

      C# 确实有“内部”修饰符,就其他在您的类之上工作的人而言,它不能替代朋友,但是当重要的是您将来扩展工厂而不是其他人的能力时,您可以将工厂和创建的类打包为一个单独的程序集,从而像“朋友”一样使用“内部”。

      而且,是的,这是使用 C# 时的一个问题。冲突的要求放弃了对旧的友好工厂类的支持,这很痛苦。如果你不能使用“内部”,而你的工厂正在渲染重量级的类,那么除了向类添加“InitInstance()”类型的方法以便扩展“制造过程”之外,真的别无选择。

      【讨论】:

        【解决方案5】:

        你必须以一种或另一种方式制造这个“黑洞”。您可以改用构造函数,这更容易。但是,我发现静态方法更好。它们几乎共享构造函数的所有架构属性,除了更好一点,因为构造函数必须始终创建一个新实例,因此构造函数无法实现某些实现抽象。

        所以,答案是:请使用静态方法! :)

        【讨论】:

          【解决方案6】:

          如果目标和工厂不在同一个程序集中,获得写入方法的部分封装的一种方法是使用私有接口实现,您可以避免使用客户端代码。

          internal interface IMyClassFactorable
          {
              string MyProperty{ set; }
          }
          
          public class MyClass : IMyClassFactorable
          {
               private string _myProperty;
               public string MyPrperty { get { return _myProperty; } }
               string IFactoryable.MyProperty { set { _myProperty = value; } }
          }
          

          如果工厂和目标在同一个程序集中,则使用内部设置器

          public class MyClass 
          {
               public string MyPrperty { get; internal set; }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-04
            • 1970-01-01
            • 2014-01-14
            相关资源
            最近更新 更多