静态工厂方法的现实用例?

时间:2010-11-16 16:23:36

标签: java oop design-patterns factory static-methods

我熟悉静态工厂方法的想法和好处,如Joshua Bloch的Effective Java所述:

  • 工厂方法具有名称,因此与构造函数不同,您可以拥有多个具有相同签名的工厂方法。
  • 工厂方法不必创建新对象;他们可以返回以前创建的对象。这适用于不可变对象或值对象。
  • 与构造函数不同,工厂方法可以返回其返回类型的任何子类型的对象。

现在我正在尝试为正在学习Java和OO原则的人解释静态工厂方法。她从具体场景而不是抽象中学习得最好。如果她能看到工作模式,解决一些问题,她就会明白。但她发现阅读上述特征的抽象列表更难以理解如何应用该模式。

你能帮我提出一个使用静态工厂方法的现实例子,这样可以清楚地获得它的好处,但是它仍然很简单,可以在介绍性的Java类中显示某人吗?

这个人确实有PL / SQL的编程经验,但从来没有学过OOP模式。

6 个答案:

答案 0 :(得分:15)

使用javax.swing.BorderFactory作为所有三个点的示例。

此类用于为swing对象创建边框。这些边框对象可以很容易地重复使用,这种工厂方法允许这样做。这是the javadoc。这个工厂是所有三点的一个很好的例子:

  • 有多种静态方法具有不同的名称,例如createEmptyBorder()createEtchedBorder()
  • 这些方法将尽可能返回先前创建的对象。在整个应用程序中使用相同的边框非常频繁。
  • Border本身实际上是一个接口,因此通过这个工厂创建的所有对象实际上都是实现此接口的类。

答案 1 :(得分:4)

第二点的教科书示例为Integer.valueOf(int)(类似于BooleanShortLongByte)。对于参数值-128到127,此方法返回缓存的实例,而不是创建新的Integer。这使得(自动)装箱/拆箱对于典型值的性能更高。

您无法使用new Integer()执行此操作,因为JLS要求每次调用new时都会创建新实例

答案 2 :(得分:4)

我目前最喜欢的这种模式的例子是GuavaImmutableList。它的实例只能由静态工厂或构建器创建。以下是一些有利的方法:

  • 由于ImmutableList没有公开任何publicprotected构造函数,因此它可以在包中进行子类化,同时不允许用户对其进行子类化(并且可能会破坏其不变性保证)。
  • 鉴于此,它的工厂方法都能够返回它的专用子类而不暴露它们的类型。
  • ImmutableList.of()工厂方法返回EmptyImmutableList的单例实例。这演示了静态工厂方法如何不需要创建新实例。
  • ImmutableList.of(E)方法返回SingletonImmutableList的实例,该实例已经过优化,因为它只能保存1个元素。
  • 其他大多数工厂方法返回RegularImmutableList
  • 它的copyOf(Collection)静态工厂方法也不总是需要创建一个新实例......如果给出的Collection本身就是ImmutableList,它就可以返回它!

答案 3 :(得分:3)

Calendar.getInstance()不是一个好的例子吗? 它根据语言环境创建BuddhistCalendar,JapaneseImperialCalendar或默认为GregorianCalendar。

答案 4 :(得分:0)

这是我不得不做的一段时间。在一次求职面试中,我被要求编制一副卡片,在那里可以洗牌。真的很简单的问题。我创建了:

Card:
  suit
  rank

Deck:
  card[]

我认为区别的因素是,任何时候都只能有52张牌。所以我将Card()的构造函数设为私有,而是创建静态工厂valueOf(suit,rank)这允许我缓存52张卡并使其成为不可变的。它教了很多重要的基础课程。

  1. 不可变
  2. 控制对象的创建
  3. 静态方法
  4. 可能是子类并从其他来源返回一张卡片。 (我没有这样做)
  5. 这类似于布尔和字节,除了我使用一个常见的作业示例来说明控制实例的重要性。我还为deck创建了一个名为newDeck()的辅助函数,因为我想显示一个实例,其中构造函数可能不需要是私有的,但是有一个帮助器静态工厂仍然很好。

    我希望这有帮助!

答案 5 :(得分:0)

简单的案例。假设你有一个操作某种打印机的类,但它不关心它是epson,canon还是其他东西。因此,您只需创建一个接口Printer,创建它的一些实现并创建一个只有一个方法的类:createPrinter。

所以,代码很简单:

   public interface Printer {
       print();
    }

    class CanonPrinter implements Printer {
       print() {
    // ...
       }
    }


    public PrinterFactory {

    Printer createPrinter() {
   if (... ) {
      return new CanonPrinter();
   } else {
      return new EpsonPrinter();
   }
}
}

客户代码:

Printer printer = PrinterFactory.createPrinter();
printer.print();

在这里,您可以从您可以操作的打印机的任何细节或管理打印的方式中抽象出clinet代码。如果一台打印机出现故障,那么它就是打印机选择的打印机。