java中的工厂模式

时间:2009-06-22 10:31:22

标签: java design-patterns factory-pattern

我正在处理应该使用Factory模式的java代码,但我并不完全相信这种模式。

我的代码执行此操作:

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

代码中的某处:

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

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

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

我觉得如果create方法是工厂类的静态方法会更好。但我也确信我的意见并非完全“正确”。

SO社区可以举例说明实例化Factory对象比使用静态创建方法更好吗?

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

5 个答案:

答案 0 :(得分:5)

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

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

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

你会:

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

然后......

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

有些观点:

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

我知道这只会解决你问题的一部分......

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

首先,你忘记了工厂模式的主要目标,我打开了四人帮的书,并说:

“定义用于创建对象的接口,但是让子类决定实例化哪个类.Pactor Method允许类将实例化延迟到子类。”

这意味着实际上您定义了一个接口,因此SomeFactoryImpl实际上应该实现在其他地方定义的接口。当你有许多需要实例化的对象但你不想关心它们是什么类型的对象时,这很方便。例如我用它们来开发一个远程swing应用程序,客户端通过序列化下载客户端VM中不存在的某些类的定义。每个类定义了一个JPanel的子类,它的特定视图但是当到达客户端时我必须找到一种方法来解释这些类而不知道它们所以我使用工厂模式来调用工厂类并让它实例化我的未知对象(通过它正在扩展由我定义的JPanel的子类。 另一个例子是生成特定于案例的对象以满足您的需求。例如(如在与此设计模式相关的维基百科页面中所述),您可以认为一个工厂为同一种对象构建对象然后是另一个工厂但是用于生成“假对象”,这将导致某种单元测试失败。 / p>

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

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

答案 3 :(得分:0)

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

  1. 它允许我创建一个工厂,配置它(创建蓝色小部件与红色小部件等),然后让它可以按需创建我的蓝色小部件,红色小部件。请注意,这与RedWidgetFactoryBlueWidgetFactory不同。配置与正在创建的对象的类型正交
  2. 它减少了在整个系统中使用一个工厂(通过静态方法访问)可能遇到的线程问题。这可能有点防守,但我发现这是一个很好的心态(特别是在相当大的系统中)。当然,这取决于您的对象是如何创建的(例如,您的工厂是否创建了共享的基础组件)

答案 4 :(得分:0)

IMO,你拥有的代码 确实是GoF Abstract Factory 模式的正确样本,即使它的使用不完全是最佳的。如果我没记错的话,GoF书籍描述了工厂(SomeFactory,SomeFactoryImpl)和产品(SomeClass)之间的关系,但保留了实例化工厂的具体细节。

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

  1. 让另一个类(可以说是“工厂经理”)根据参数(例如JDBC中的DriverManager)或其他上下文信息选择工厂实现。
  2. 使用某种依赖注入框架。
  3. 如果选择#1,我个人通常会尝试在JDBC之后对其进行建模,其中:

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

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

    要将它与问题联系起来,可以通过调用

    来使用JDBC
    new OracleDriver().connect(...)
    

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

    这个问题过去一直困扰着我,直到有一天我意识到这种模式实际上没有明确地谈论工厂的创建方式。

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