2008-10-21 232 views
82

在我們的一些項目中,有一個類層次結構在沿着鏈條添加更多參數。在底部,一些類可以有多達30個參數,其中28個只傳遞給超級構造函數。使用Java管理具有多個參數的構造函數

我會承認,通過類似Guice的自動化DI會很好,但是由於某些技術原因,這些特定的項目都被限制爲Java。

按類型按字母順序組織參數的約定不起作用,因爲如果某個類型被重構(您爲參數2傳入的圓現在是一個形狀),它可能突然出現故障。

這個問題可能是特定的,並且充滿了「如果這是你的問題,你在設計層面上做錯了」的批評,但我只是在尋找任何觀點。

回答

219

的生成器設計模式可能會有幫助。請看下面的例子

public class StudentBuilder 
{ 
    private String _name; 
    private int _age = 14;  // this has a default 
    private String _motto = ""; // most students don't have one 

    public StudentBuilder() { } 

    public Student buildStudent() 
    { 
     return new Student(_name, _age, _motto); 
    } 

    public StudentBuilder name(String _name) 
    { 
     this._name = _name; 
     return this; 
    } 

    public StudentBuilder age(int _age) 
    { 
     this._age = _age; 
     return this; 
    } 

    public StudentBuilder motto(String _motto) 
    { 
     this._motto = _motto; 
     return this; 
    } 
} 

這讓我們寫代碼像

Student s1 = new StudentBuilder().name("Eli").buildStudent(); 
Student s2 = new StudentBuilder() 
       .name("Spicoli") 
       .age(16) 
       .motto("Aloha, Mr Hand") 
       .buildStudent(); 

如果我們離開過必填字段(大概是必需的名稱),那麼我們可以讓學生構造函數拋出異常。 它讓我們擁有默認/可選參數,無需跟蹤任何類型的參數順序,因爲這些調用的任何順序都可以很好地工作。

+8

當然,對於靜態導入,您甚至無需「看到」這些「構建器」。例如,您可以使用返回構建器的靜態方法名稱(String name)和返回學生的Student(StudentBuilder)。因此,學生(姓名(「喬」)。年齡(15).motto(「我已經溼了自己」)); – 2008-10-21 20:46:34

1

重構減少參數和深度的繼承層次結構的數量幾乎是我能想到的,因爲沒有什麼能真正幫助保持20個參數。在查看文檔時,您只需要每一個電話。

你可以做的一件事是將一些邏輯分組的參數分組到自己的高級對象中,但這有它自己的問題。

3

最好的解決方案是在構造函數中沒有太多參數。只有構造函數真正需要的參數是需要正確初始化對象的參數。你可以有多個參數的構造函數,但也有一個只有最小參數的構造函數。額外的構造函數調用這個簡單的構造函數,並在那些設置器之後設置其他參數。通過這種方式,您可以避免帶有越來越多參數的鏈式問題,但也可以使用一些便利構造函數。

4

由於您受限於Java 1.4,如果您想要DI,那麼Spring將是一個非常不錯的選擇。 DI僅在構造函數參數爲服務的地方或在運行時不發生變化的地方有用。

如果你有所有這些不同的構造函數,因爲你需要關於如何構造一個對象的變量選項,你應該認真考慮使用Builder模式。

+0

參數大多是你提到的服務,所以DI就是我所需要的。我認爲其他答案中提到的Builder模式正是我所希望的。 – 2008-10-21 20:08:43

21

你可以在對象中封裝相關參數嗎?

例如,如果參數都像

 

MyClass(String house, String street, String town, String postcode, String country, int foo, double bar) { 
    super(String house, String street, String town, String postcode, String country); 
    this.foo = foo; 
    this.bar = bar; 
 

,那麼你可以代替有:

 

MyClass(Address homeAddress, int foo, double bar) { 
    super(homeAddress); 
    this.foo = foo; 
    this.bar = bar; 
} 
 
5

好,使用生成器模式可能是一個解決

但是一旦你達到了20到30個參數,我猜測參數之間有很高的關係。所以(按照建議)將它們包裝成邏輯上合理的數據對象可能是最有意義的。這樣數據對象就可以檢查參數之間約束的有效性。

對於我過去的所有項目,一旦我發現有太多參數(而這8個不是28!),我就可以通過創建更好的數據模型來清理代碼。