为什么工厂方法设计模式比拥有类和分别调用它们更有用?


32

在“四人帮”设计模式中,有Factory方法:

class Factory(product)
  case product
  when a
    new A
  when b
    new B
  when c
    new C
end

new Factory(a)

这是为什么比有三类,更加有用ab以及c和单独叫他们?


1
你到底是什么意思 为什么不实例化这三个呢?你是这个意思吗?
Neil

1
@Neil不,在工厂模式中,所有类都作为同级存在。为什么要致电工厂间接访问a,b,c类?
2013年

3
在我看来,这实际上不像是工厂方法模式,如果有的话它更接近抽象工厂
jk。

2
因为在设计时,您不知道需要实例化这3个类中的哪一个。
MrWhite 2013年

2
@jk:不,实际上不是。程序员
.stackexchange.com / questions / 81838 /…

Answers:


54

因为您的示例还不够复杂。对于这样一个简单的场景,使用高级模式甚至都没有意义。

但是,如果您不仅仅需要了解构成A,B或C的产品,而且不能直接访问该知识,那么它很有用。然后,您将使用工厂充当生产所需对象的知识中心。

也许这些对象需要工厂可以提供的对某个对象X的引用,但是您想要构造A,B或C的地方的代码无法或不应该访问X。也许当您拥有X时您创建A和B,但如果您输入Y,则创建C。

还应考虑某些对象可能需要20个依赖关系才能创建;然后怎样呢?在不应该访问它们的地方寻找这些依赖可能是有问题的。


13
+1是为了清楚表明Factory模式并非始终是最佳方法。
尼尔

1
因为您的示例还不够复杂。对于这样一个简单的场景,使用高级模式甚至都没有意义。那么在这种情况下您会怎么做?内联条件构造?
pdr 2013年

它可以只是获取产品并返回使它可重复使用所需的方法,因此它不必是内联的。如果这种方法变得更大,或者在其他几个类中使用,则可以将其重构为其他类。
Mateusz

由于某种原因,该模式称为“工厂方法”。该方法不必是工厂类中的另一类(尽管通常是这样)。
pdr 2013年

我错过了其中的“方法”,所以您是正确的先生。
Mateusz

23

工厂模式通常比这更复杂。工厂根据某些条件决定要创建/返回的实例。相反,当您不使用工厂时,您将在代码的多个位置重复使用该代码。

例如,考虑以下内容:您需要从一个数据库中加载数据,但是您需要一个中央数据库来集成大量数据,而每个开发PC的内存中只有一个较小的中央数据库。在你的代码,你问一个工厂来获得一个 DB-手柄和工厂的回报取决于例如一个配置文件,其中的一个。


20

Factory Method模式从调用类抽象了决策过程。这有几个优点:

重用。如果我想在许多地方实例化,则不必重复我的条件,因此,当我要添加一个新的类时,我不会冒丢失一个类的风险。

单元可测试性。我可以为工厂编写3个测试,以确保它在正确的条件下返回正确的类型,然后仅对我的调用类进行测试,以查看它是否调用了工厂,然后对返回的类进行了必需的方法测试。它不需要了解工厂本身或具体类的实现。

可扩展性。当某人决定我们需要向该工厂添加新的类D时,无需告知任何调用代码,单元测试或实现。我们只需创建一个新的D类并扩展我们的工厂方法即可。这就是开闭原理的定义。

如果情况需要,您甚至可以创建一个新的工厂类并使其可热交换-例如,如果您希望能够在测试时打开和关闭D类。我只遇到过一次这种情况,但这非常有用。

如前所述,工厂模式并非总是可行的方式。但是,无论您在何处看到条件实例化,都应该花点时间思考一下。


14

工厂模式的主要优点是双重的:

  1. 需要产品实施的地方不需要知道如何构造产品。工厂保存该信息。

    您是否想知道要传递给特定构造函数的参数?或者您必须注入哪些依赖项?还是在数据库完全配置后如何在数据库中注册实现类?没有?让工厂照看所有这些东西。

  2. 需要产品实现的地方在模块描述时(即,在编译时)不需要知道实现类的名称。

    因此,a无需任何关系A;“构建什么”可以根据所需的非功能属性来描述,而不仅仅是名称。这更加灵活。

缺点是,在知道要制造什么以及如何做的地方,使用工厂时会变得更加复杂。但是,解决方法很简单:在没有意义的情况下不要使用工厂!


2

我想从作为“人”的类来考虑设计模式,而模式是人们彼此交谈的方式。

因此,对我而言,工厂模式就像一家中介公司。您有一个需要可变数量工人的人。这个人可能知道他们所雇用的人所需的一些信息,仅此而已。

因此,当他们需要新员工时,他们会致电招聘机构并告诉他们他们需要什么。现在,要真正雇用某人,您需要了解很多东西-福利,资格验证等。但是,雇用人并不需要知道所有这些-雇用中介可以处理所有这些。

同样,使用Factory可使使用者创建新对象,而不必知道其创建方式或它们的依赖关系的详细信息-他们只需要提供实际所需的信息即可。

礼貌


1

工厂模式是最被过度使用和滥用的设计模式。

我遇到过无数情况,当简单的构造函数就足够了时,可以对Factory类进行编码。

不要使用工厂类,除非:

  • 您依赖于一种外部资源,但是您还不确定确切的资源。
  • 施工非常昂贵,您想一次建造并多次重复使用。
  • 构造新实例取决于已构造的实例(例如,您只能有五个连接,或者应使用比最后使用的编号大一个的连接ID号)。

0

实例化子类时使用Factory Method,并且客户端代码不负责确定实例化哪个特定的子类。

这很有用,因为它使您无需在需要更改实例化类时更改客户端代码。更改现有代码是不好的做法,因为它通常容易出错。

一个示例是子类,其中每个子类都以升序对数据进行排序,但方式不同。对于特定种类的数据,每种方式都是最佳的。例如:部分排序的数据,数字数据等。客户端代码是仅处理数据打印的类。拥有决定在客户端类中实例化哪个排序类的代码会使它成为一个复杂的类。换句话说,在这种情况下,要确定一个以上的分类是最佳的并打印数据。通过将确定实例化哪个排序类的代码放入Factory类中,它可以将关注点分离开,从而使您无需在每次需要更改实例化排序子类时都更改客户端类。

如果您可以预见自己的自我改变会在如何实例化什么类或实例化什么类的过程中发生变化,那么这是掩盖您的烦恼的一种方式,那么可以使用工厂类。它有助于使您的班级专注于其职责,从而确保您不太可能需要修改不相关的现有代码。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.