2012-02-26 98 views
3

我的問題與此處發佈的問題幾乎完全相同:Abstract class with final uninitialized field我喜歡解決方案。然而,我的問題有點複雜,因爲抽象類有多個不同類型的最終字段。例如,我有四個int,兩個int[]和兩個double。什麼是強制子類初始化這些變量的最好方法?在子類中初始化變化類型的'最終'字段

選項,我認爲:

  • 轉換爲字符串的所有領域,並用Map
  • 傳遞有一個很長的父類的構造
  • 創建的helper類將作爲一個包裝和封裝所有的值,然後將這個類的一個實例傳遞給基類

第一個選項不是很優雅,而且看起來有點複雜,esp特別是與數組。第二種選擇非常單調乏味,第三種選擇看起來像是我過度了。

有沒有一個「正確」的方式來做到這一點?或者,如果不是,三種選擇中哪一種最優雅?

回答

5

我會與第二,「有一個非常長的超類構造函數。」如果我們遵循question you referenced中詳述的方法,超類的構造函數是protected,並不意味着被類層次結構或包外部的任何東西調用。我的感覺總是,一旦某種東西沒有暴露在這個邊界之外 - 即它不是「API」的一部分 - 那麼它看起來並不重要。讓它有八種不同類型的參數,甚至更多。是的,它在包內是可見的,但是從原始解決方案中可以清楚地看到,該構造函數並不意味着被其他子類調用。這是非public知名度的另一個動機。

當然,當涉及到public的東西時,你做直覺乾淨的本能是正確的。你問這個問題的事實表明你有正確的本能。

+1

這很有道理。這使得控制子類中的值非常容易,並且繼續構建子類很簡單。謝謝! – williamg 2012-02-26 02:04:10

+0

很高興提供幫助。總的來說,我的建議是:爲公衆保持高標準(優雅,模式等),並且不要害怕在私人/受保護的領域削減幾個角落。 – 2012-02-26 03:25:51

1

但是,我的問題有點複雜,因爲抽象的 類有多個不同類型的最終字段。

我不確定我是否理解您的情況中增加的複雜性,但我將您的問題解釋爲:我不想在抽象構造函數上有大量參數。一種可能的方法是爲具體子類使用的抽象類設置Builder。然後將構建器「傳遞」給抽象構造器以設置最終字段。

0

當我需要一個不可變的對象(所有成員都是final),並在構造函數中使用許多不同的參數時,我通常使用Builder模式。

在這種情況下,您可以使建設者相互分類,這樣您仍然可以保持擴展能力。

舉個例子,你可以看到用於ImmutableCollection的Guava API Builder。 或者,如果你不要求更改的,這裏是CacheBuilder也是從同一個庫取一個例子:

Cache<Key, Graph> graphs = CacheBuilder.newBuilder() 
    .concurrencyLevel(4) 
    .weakKeys() 
    .maximumSize(10000) 
    .expireAfterWrite(10, TimeUnit.MINUTES) 
    .build(
     new CacheLoader<Key, Graph>() { 
     public Graph load(Key key) throws AnyException { 
      return createExpensiveGraph(key); 
     } 
     }); 

正如你可以看到使用的助洗劑代替了需要在6個參數通過在構造函數中並提供更多可讀/可用的代碼。

如果你還不想使用構建我會選擇去(3)爲防止​​一些維持很長的構造

2

這裏的麻煩的是另一種選擇,假設你擁有所有的控制類涉及:抽象出來,超類中的字段,宣佈它們在子類中,有點像這樣...

abstract class SuperClass { 
    abstract int[] getFooArray(); // not public! 
    abstract int getBar(); 
} 

,然後就在每個子類中那些的定義字段,覆蓋的方法來回報他們。

是的,它會涉及一些代碼重複,但最終可能會比一個無法理解的長構造函數更乾淨,並且您複製的代碼並不是很多 - 一個字段,一行代碼方法返回該字段。