簡體   English   中英

靜態工廠方法的現實用例?

[英]Realistic use case for static factory method?

我熟悉靜態工廠方法的想法和好處,如Joshua Bloch的Effective Java中所述

  • 工廠方法具有名稱,因此與構造函數不同,您可以使用多個具有相同簽名的工廠方法。
  • 工廠方法不必創建新對象; 他們可以返回以前創建的對象。 這適用於不可變對象或值對象。
  • 與構造函數不同,工廠方法可以返回其返回類型的任何子類型的對象。

現在,我正在嘗試為正在學習Java和OO原則的人解釋靜態工廠方法。 她從具體場景而不是抽象中學習得最好。 如果她能看到工作模式,解決一些問題,她就會明白。 但她發現更難以閱讀上述特征的抽象列表來理解如何應用模式。

你能幫我提出一個使用靜態工廠方法的現實例子,它可以使它的好處變得清晰,但是它仍然足夠簡單,可以在介紹性的Java類中顯示某些人嗎?

這個人確實有PL / SQL的編程經驗,但從來沒有學過OOP模式。

使用javax.swing.BorderFactory作為所有三個點的示例。

此類用於為swing對象創建邊框。 這些邊框對象可以很容易地重復使用,這種工廠方法允許這樣做。 這是javadoc 這個工廠是所有三點的一個很好的例子:

  • 有多個靜態方法具有不同的名稱,如createEmptyBorder()createEtchedBorder()
  • 這些方法將盡可能返回先前創建的對象。 在整個應用程序中使用相同的邊框非常頻繁。
  • Border本身實際上是一個接口,因此通過此工廠創建的所有對象實際上是實現此接口的類。

第二個點的教科書示例是Integer.valueOf(int) (類似於BooleanShortLongByte )。 對於參數值-128到127,此方法返回緩存的實例,而不是創建新的Integer 這使得(自動)裝箱/拆箱對於典型值更加高效。

你不能用new Integer()做到這一點,因為JLS要求new在每次調用時都創建一個新實例

我目前最喜歡的這種模式的例子是GuavaImmutableList 它的實例只能由靜態工廠或構建器創建。 以下是一些有利的方法:

  • 由於ImmutableList不公開任何publicprotected構造函數,因此它可以在包中進行子類化,同時不允許用戶對其進行子類化(並且可能會破壞其不變性保證)。
  • 鑒於此,它的工廠方法都能夠返回它的專用子類而不暴露它們的類型。
  • 它的ImmutableList.of()工廠方法返回EmptyImmutableList的單例實例。 這演示了靜態工廠方法如何不需要創建新實例。
  • 它的ImmutableList.of(E)方法返回一個SingletonImmutableList實例,該實例經過優化,因為它只能保存1個元素。
  • 它的大多數其他工廠方法都返回一個RegularImmutableList
  • 它的copyOf(Collection)靜態工廠方法也並不總是需要創建一個新實例......如果給出它的Collection本身就是一個ImmutableList ,它就可以返回它!

Calendar.getInstance()不是一個很好的例子嗎? 它根據語言環境創建BuddhistCalendar,JapaneseImperialCalendar或默認為GregorianCalendar。

這是我不得不做的一件事。 在一次求職面試中,我被要求編制一副卡片,在那里可以洗牌。 真的很簡單的問題。 我建立:

Card:
  suit
  rank

Deck:
  card[]

我認為區別的因素是,任何時候都只能有52張牌。 所以我將Card()的構造函數設為私有,而是創建靜態工廠valueOf(suit,rank)這允許我緩存52張卡並使其成為不可變的。 它教了很多重要的基礎課程。

  1. 一成不變
  2. 控制對象的創建
  3. 靜態方法
  4. 可能是子類並從另一個來源返回一張卡片。 (我沒有這樣做)

這類似於布爾和字節,除了我使用一個常見的作業示例來說明控制實例的重要性。 我還為deck創建了一個名為newDeck()的輔助函數,因為我想顯示一個實例,其中構造函數可能不需要是私有的,但是擁有一個幫助器靜態工廠仍然很好。

我希望這有幫助!

這個簡單的案例。 假設你有一個操作某種打印機的類,但它不關心它是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代碼。 它是PrinterFactory,如果一個例如出現故障,他會關心選擇什么打印機。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM