簡體   English   中英

具有所有類屬性的構造函數或帶有setter的默認構造函數?

[英]Constructor with all class properties or default constructor with setters?

以下是兩種方法:

  • 具有所有類屬性的構造函數

優點:我必須輸入確切數量的參數類型,所以如果我發出錯誤,編譯器會警告我(順便說一下,有沒有辦法防止錯誤地在參數列表上切換兩個Integer的問題?)

缺點:如果我有很多屬性,那么實例化行可能變得非常長並且可能跨越兩行或更多行

  • setter和默認的空構造函數

優點:我可以清楚地看到我正在設置的內容,所以如果我做錯了什么我可以在輸入時立即查明它(我不能在切換兩個相同類型的變量時出現前一個錯誤)

缺點:具有大量屬性的對象的實例化可能需要幾行(不知道這是否真的是一個con),如果我忘記設置屬性,編譯器就不會說任何內容。

你會做什么以及為什么? 你知道任何光模式(考慮到應該在每次實例化7個以上的屬性時使用它)嗎? 我問這個因為我傾向於不喜歡大型構造函數,我無法快速找出我正在尋找的變量的位置,另一方面我發現“set all properties”容易遺漏一些屬性。

請隨意在優缺點中論證我的假設,因為它們只是我的想法:)

更新 - 我發現的一個與此相關的問題: 構建大的不可變對象,而不使用具有長參數列表的構造函數

您錯過了擁有帶有大量參數的構造函數的最大專家:它允許您創建不可變類型。

創建不可變類型而不會產生巨大構造函數的常規方法是使用輔助類型 - 一個構建器 ,它維護您在最終對象中需要的值,然后在准備好時構建不可變對象。

您可以查看Joshua Bloch倡導的Builder模式,並在Effective Java中進行了描述。 http://developers.sun.com/learning/javaoneonline/2007/pdf/TS-2689.pdf上有一些主要內容的演示文稿; 毫無疑問,你可以挖掘出更好的參考。

基本上,你有另一個類,可能是一個內部類,它提供了在設置屬性后命名的方法,並返回原始構建器,以便鏈接調用。 它構成了相當可讀的代碼塊。

例如,假設我有一個帶有一些屬性的簡單Message 構造它的客戶端代碼可以使用構建器來准備Message ,如下所示:

Message message = new Message.Builder()
    .sender( new User( ... ) )
    .recipient( new User( ... ) )
    .subject( "Hello, world!" )
    .text( messageText )
    .build();

Message.Builder的片段可能類似於以下內容:

public class Builder {

    private User sender = null;
    // Other properties

    public Builder sender( User sender ) {
        this.sender = sender;
        return this;
    }
    // Methods for other properties

    public Message build() {
        Message message = new Message();
        message.setSender( sender );
        // Set the other properties
        return message;
    }

}

最近關於API可用性的學術研究(CMU和Microsoft)表明,使用setter的默認構造函數將是可用性的方法。 這來自Jeff Stylos和Steven Clarke撰寫的“對象構造函數中需要參數的可用性含義”,並在國際軟件工程大會上發表:

摘要 :API的可用性對程序員的生產力越來越重要。 基於對特定API的可用性研究的經驗,探索了用於研究許多API共有的設計選擇的可用性的技術。 進行了一項比較研究,以評估專業程序員如何在對象的構造函數中使用具有必需參數的API,而不是無參數的“默認”構造函數。 假設通過引導程序員正確使用對象並防止錯誤,所需參數將創建更多可用和自我文檔化的API。 然而,在該研究中,發現與預期相反,程序員強烈傾向於使用不需要構造函數參數的API更有效。 使用認知維度框架分析參與者的行為,並揭示所需的構造函數參數干擾共同的學習策略,導致不合需要的過早承諾。

你在帖子中提到它,但我認為這是一個值得關注的重點:除非每個輸入參數都是不同類型,否則巨大構造函數的一個大問題就是轉換幾個變量非常容易。 編譯器是一個不可靠的安全網 - 它會捕獲一些錯誤,但是那些漏掉的錯誤將更加難以識別和調試。 特別是因為巨大的構造函數的輸入列表是非常不透明的,除非你在另一個窗口中打開了API。

getter和setter非常容易調試,特別是如果你提出了在沒有正確填充對象的情況下拋出運行時異常的安全措施。 而且我是“易於調試”的忠實粉絲。

在此線程之前,我從未聽說過Rob提到的Builder模式。 從來沒有使用過它(很明顯),但這很有趣。

出於前面提到的不變性原因,我更喜歡使用構造函數參數。 如果這給你一個帶有很多參數的構造函數(比如說超過四個),那對我來說就是代碼味道:其中一些參數應該捆綁在一起成為它們自己的類型。

例如,如果你有這樣的東西:

class Contact
{
    public Contact(string firstName, string lastName, string phoneNumber,
        string street, string city, string state, int zipCode) { ... }
}

我將它重構為:

class Contact
{
    public Contact(Person person, PhoneNumber number, Address address) { ... }
}

class Person
{
    public Person(string firstName, string lastName) { ... }
}

class PhoneNumber
{
    public PhoneNumber(string digits) { ... }
}

class Address
{
    public Address(string street, string city, string state, int zipCode) { ... }
}

在OOP代碼庫中,太大的類是一個非常常見的設計問題。

還有其他方面。 如果你想在設計時而不是僅僅在運行時使用你的類來處理某些事情,例如在Object Palette中添加你的類作為對象(這是使用Netbeans的Java),你需要提供一個無參數的構造函數為了能夠這樣做。

這里還有其他策略。 在試圖弄清楚如何處理大量參數之前,我認為重新訪問您的設計並查看您的課程是否做得太多非常重要。 看看你是否可以將一些參數組合成一個新類,並將一些行為移到該類中。

setter和默認的空構造函數

JRL傾向於觸及它 ,但考慮使用setter的一個原因是讓對象符合JavaBean規范 這使得實例可以通過內省工具進行編輯 ,並使用某些序列化技術進行持久

誰說你做不到兩者兼而有之? 我會說強制屬性進入構造函數,可選的屬性用setter處理。 BTW,誰說你每個房產總需要一個二人? 如果兩個屬性在概念上屬於一個,為什么不將它們組合在一起?

我也喜歡Builder模式,但最重要的規則是:始終使用你的大腦並找到最適合特定問題的設計。 沒有一個通用的解決方案。

暫無
暫無

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

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