将这个班级称为“工厂”是否令人困惑?

时间:2009-11-16 20:06:41

标签: c# naming-conventions design-patterns factory

我对 factory 的理解是它封装了所有继承公共抽象类或接口的具体类的实例化。这允许客户端与确定要创建哪个具体类的过程分离,这反过来意味着您可以从程序中添加或删除具体类,而无需更改客户端的代码。你可能不得不改变工厂,但工厂是“专门建造的”,实际上只有一个改变的理由 - 添加/删除了一个具体的类。

我已经构建了一些实际上封装了对象实例化的类,但原因不同:对象很难实例化。目前,我将这些类称为“工厂”,但我担心这可能是一种误称,并会混淆其他可能会查看我的代码的程序员。我的“工厂”类没有决定实例化哪个具体类,它们保证一系列对象将以正确的顺序实例化,并且当我调用new()时,正确的类将被传递给正确的构造函数。

例如,对于我正在处理的MVVM项目,我编写了一个类来确保我的SetupView被正确实例化。它看起来像这样:

public class SetupViewFactory
{
    public SetupView CreateView(DatabaseModel databaseModel, SettingsModel settingsModel, ViewUtilities viewUtilities)
    {
        var setupViewModel = new SetupViewModel(databaseModel, settingsModel, viewUtilities);
        var setupView = new SetupView();
        setupView.DataContext = setupViewModel;
        return setupView;
    }
}

将此称为“工厂”是否令人困惑?它不会决定几个可能的具体类,并且它的返回类型不是接口或抽象类型,但它确实封装了对象实例化

如果它不是“工厂”,它是什么?


修改

很多人都认为这实际上是构建器模式。

来自dofactory的构建器模式的定义如下:

  

将复杂对象的构造与其表示分开,以便相同的构造过程可以创建不同的表示。

这似乎也有点延伸。困扰我的是“不同的表现形式”。我的目的不是抽象构建视图的过程(不是那个不值得的目标)。我只是想在一个地方设置创建特定视图的逻辑,这样如果任何成分或创建该视图的过程发生变化,我只需要更改这一个类。构建器模式似乎真的在说,“让我们创建一个创建视图的一般过程,然后您可以为您创建的任何视图执行相同的基本过程。”很好,但那不是我在这里做的。


修改2

我刚在Wikipedia article on Dependency Injection找到了一个有趣的例子。

在“Manually Injected依赖”下,它包含以下类:

public class CarFactory {

    public static Car buildCar() {
        return new Car(new SimpleEngine());
    }

}

这几乎完全我的用法(并且,不,我没有写维基文章:))。

有趣的是,这是此代码后面的评论:

  

在上面的代码中,工厂负责组装汽车,并将发动机注入汽车。这让汽车免于了解如何制造发动机,尽管现在CarFactory必须知道发动机的结构。可以创建一个EngineFactory,但这只会创建工厂之间的依赖关系。所以问题仍然存在,但至少已转移到工厂构建器对象。 [我的重点]

所以,这告诉我,至少我不是唯一一个想创建一个类来帮助将东西注入另一个类的人,而我并不是唯一一个试图将这个类命名为工厂的人。

9 个答案:

答案 0 :(得分:4)

在我看来,你所拥有的更多是 Builder 模式而不是工厂模式。

答案 1 :(得分:4)

对于我而言,这与SetupView实例的构造函数没什么不同。也许从你的例子中省略了太多的代码上下文,但是我不明白为什么你在那里拥有的东西不能简单地写成构造函数,并且参数作为args传递给构造函数。

严格按照GoF模式判断,我认为它错过了Factory上的标记有两个原因:

  1. 没有相关/从属对象系列
  2. 确实指定了具体类
  3. 关于Builder,我认为它在产品差异方面缺失。

    当我教授设计模式课程时,我告诉学生在尝试确定“最适合”时,不仅要考虑模式的意图,而应该考虑适用性和结构/参与者。意图可以帮助你排除事情,但适用性和结构/参与者将帮助你回家。

    如果您可以确定您的设计的哪个部分在(抽象)工厂或构建器中履行参与者的各种角色,那么您已经为使用该命名法做了很好的案例。

答案 2 :(得分:1)

GoF称之为“Builder

答案 3 :(得分:1)

我认为,这是一个“工厂”。当我查看类声明时,我很高兴看到这是一个“工厂”,而且它是SetupView对象的“工厂”。所以我知道这个工厂将为我提供具体且正确构建的SetupView实例。

答案 4 :(得分:1)

“工厂”是封装新对象实例化的任何东西。为什么或对象是什么并不重要。最常见的用途是如您所述,但其他不符合该描述的用途也可称为工厂。基本的想法,(我认为除了最肛门或挑剔的开发人员之外不会误解),就是为你实例化新对象......

答案 5 :(得分:1)

这对我来说似乎有点奇怪。它不是一个抽象的工厂,但它也不太适合Builder模式。对我来说最有意义的不是使用CreateView方法的SetupViewFactory,而是将此方法移动到SetupView类并使其成为静态。所以你有......

public class SetupView
{
    public static SetupView CreateView(DatabaseModel databaseModel, SettingsModel settingsModel, ViewUtilities viewUtilities)
    {
        var setupViewModel = new SetupViewModel(databaseModel, settingsModel, viewUtilities);
        var setupView = new SetupView();
        setupView.DataContext = setupViewModel;
        return setupView;
    }
}

现在您拥有所谓的静态工厂或工厂方法。您可以更进一步并对SetupView构造函数进行私有化,以便获取SetupView实例的唯一方法是调用工厂方法。

回应OP的评论:

如果需要分离,我会避免在代码的这一部分的任何地方创建SetupViewModel。相反,只需传入要与SetupView关联的SetupViewModel而不是传递给SetupViewModel构造函数的组成属性。所以代码变成......

public class SetupView
{
    public static SetupView CreateView(SetupViewModel model)
    {
        var setupView = new SetupView(); { DataContext = model };
        return setupView;
    }
}

答案 6 :(得分:1)

为什么不使用简单构造函数的两个类?

 public class SetupViewModel {
      public SetupViewModel(DatabaseModel databaseModel, SettingsModel settingsModel, ViewUtilities viewUtilities) {
          this.DatabaseModel = databaseModel;
          this.SettingsModel = settingsModel;
          this.ViewUtilities = viewUtilities;
      }
 }

 public class SetupView {         
      public SetupView(SetupViewModel model) {              
          this.DataContext = model;
      }
 }

这样,两个类都清楚地说明了他们需要构建的内容。

答案 7 :(得分:0)

你可以称之为“巫师”。

答案 8 :(得分:0)

我倾向于同意Jason的观点。对我而言,它更像是一个Builder模式,但如果你将SetupView变成一个界面,它就更像是一个Factory模式。 Factory模式的关键是让Factory模式完成所有工作,决定从函数调用返回什么。所以我认为你必须在给定输入参数的各种选项之间选择一个开关。