6

我正在使用据称使用工厂模式的 java 代码,但我并不完全相信该模式。

我的代码是这样做的:

// the factory
class SomeFactoryImpl {
   Set<SomeClass> getSomeListOfObjects();
}

在代码的某处:

{ ...
    SomeFactory factory = new SomeFactoryImpl();
    Set<SomeClass> list = factory.getSomeListOfObjects();
}

我正在思考的一点是,如果工厂类没有静态 create() 方法,那么将需要实例化一个工厂,IMO 应该与实例化对象本身一样复杂。

我认为这样的工厂可以返回要生产的对象集合的论点不够好。如果需要在从工厂实际创建对象之前创建工厂实例,我觉得可以有更干净的解决方法。

我觉得create方法最好是工厂类的静态方法。但我也确信我的观点并不完全“正确”。

那么 SO 社区能否给出实例化工厂对象比使用静态创建方法更好的示例?

另外,我遇​​到了一个类似问题的答案,其中列出了这些链接和答案:所以我需要通过代码示例清楚地了解FactoryMethodPatternFactoryMethodCreationMethod之间的区别。

4

5 回答 5

5

使用工厂实例显示了与依赖注入结合使用时的真正好处。

所以在你的例子中,而不是:

{ ...
    SomeFactory factory = new SomeFactoryImpl();
    Set<SomeClass> list = factory.getSomeListOfObjects();
}

你将会拥有:

public ThisClass(SomeFactory someFactory) {
    this.factory = someFactory;
}   

然后后来...

{ ...
    Set<SomeClass> list = factory.getSomeListOfObjects();
}

几点:

  • 在这种情况下,您的类没有对具体工厂的任何引用,也不需要知道 SomeFactoryImpl,它只知道抽象的 SomeFactory。
  • 在这种情况下,传递的工厂实例可以基于实例进行配置,而不是基于静态,这往往是(在我看来)处理它的更好方法。如果您可以使工厂实例不可变,那么您可以真正减少多线程的担忧。
  • 有一个静态调用来给你一个实例并没有更好,对创建它的类的引用仍然是一个具体的实现细节,它只是更高——尽管这可能使它足够高来解决你的问题。

我知道这只能解决你问题的一个子集......

于 2009-06-22T11:31:15.270 回答
1

我想,创建对象的静态方法是最流行的方法,但也有一些用例首先创建工厂实例是有意义的。例如,如果您想将其与注册表结合(应该允许多个注册表共存)。

此外,如果工厂依赖于一些动态上下文信息(数据库连接,...),我认为最好让工厂实例处理这个问题。

于 2009-06-22T10:39:46.920 回答
1

首先,您忘记了工厂模式的主要目标,我打开了四人帮的书,上面写着:

“定义用于创建对象的接口,但让子类决定要实例化哪个类。工厂方法让类将实例化推迟到子类。”

这意味着实际上你定义了一个接口,所以SomeFactoryImpl实际上应该实现在其他地方定义的接口。当您有许多需要实例化的对象但您不想关心它们是哪种对象时,这会很方便。例如,我使用它们开发了一个远程摇摆应用程序,其中客户端通过序列化下载客户端 VM 中不存在的某些类的定义。每个类都定义了一个 JPanel 的子类,它的特定视图但是当到达客户端时,我必须找到一种方法来实例化这些类而不知道它们,所以我使用工厂模式来调用工厂类并让它实例化我的 uknown 对象(通过它正在扩展我定义的 JPanel 的子类)。另一个例子是生成特定于案例的对象以满足您的需求。

但是,您也可以使用静态方法解决您的特定问题,但考虑将生成项目的部分与在大项目中使用它们的部分分开。当然,开发客户端部分的人应该只知道使用了哪个工厂接口,并且只知道这一点以使用其他部分中定义的所有对象。

创建模式是一种“便利”模式,仅用于定义构造函数的自定义版本,而不用担心使用标准定义(方法的名称等于类的名称),但它没有什么特别的。只是一种不同的方式来实例化对象.. 创建模式实际上并不能解决任何类型的特定问题(不包括具有相同数量和类型参数的构造函数)。

于 2009-06-22T10:51:02.310 回答
0

这就是我创建工厂对象实例的原因

  1. 它允许我创建一个工厂,对其进行配置(以创建蓝色小部件与红色小部件等),然后可以根据需要创建我的蓝色小部件和红色小部件。请注意,这与具有RedWidgetFactory,不同BlueWidgetFactory。配置与正在创建的对象的类型正交
  2. 它减少了在整个系统中使用一个工厂(通过静态方法访问)时可能遇到的线程问题。这可能有点防御性,但我发现这是一个很好的心态(尤其是在相当大的系统中)。当然,这取决于您的对象是如何创建的(例如,您的工厂是否创建了共享的底层组件)
于 2009-06-22T11:11:09.307 回答
0

IMO,您拥有的代码确实是 GoF抽象工厂模式的适当样本,即使它的使用并非完全最佳。如果我没记错的话,GoF 的书描述了工厂(SomeFactory、SomeFactoryImpl)和产品(SomeClass)之间的关系,但没有公开实例化工厂的细节。

如果您拥有的是不会被广泛使用的内部 API,那么您拥有的可能就足够了。否则,您可以:

  1. 让另一个类(可以说是“工厂管理器”)根据参数(例如,JDBC 中的 DriverManager)或其他上下文信息来选择您的工厂实现。
  2. 使用某种依赖注入框架。

如果使用#1,我个人通常会尝试在 JDBC 之后对其进行建模,其中:

  • Driver将是抽象工厂
  • Connections, Statementsetc 是产品
  • DriverManager(GoF 书中未明确指定)是根据传入的 JDBC URL 为您选择工厂的实用程序类

(在这种情况下,如果您像大多数人一样使用这些方法,DriverManager那么也会继续为您创建产品。)getConnection(...)

要将其与您的问题联系起来,可以通过调用来使用 JDBC

new OracleDriver().connect(...)

但是正如您所指出的,这是次优的,并且在某种程度上违背了使用抽象工厂模式的目的。

这个问题曾经也很困扰我,直到有一天我意识到那个模式实际上并没有明确地谈论工厂是如何创建的。

我希望这回答了你的问题。

于 2009-06-22T11:11:42.470 回答