簡體   English   中英

用可選參數構造一個類

[英]Structuring a class with optional parameters

在閱讀有關構建器模式的本頁時 ,我注意到該類包含可選參數。

例:

public static class Builder {
        // Required parameters
        private final int servingSize;
        private final int servings;

        // Optional parameters - initialized to default values
        private int calories      = 0;
        private int fat           = 0;
        private int carbohydrate  = 0;
        private int sodium        = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings    = servings;
        }

如果刪除構建器模式,則我們的類如下所示:

 public final class NutritionFacts
 {
        private final int servingSize;
        private final int servings;
        private final AbstractMap<String,int> optionalFacts;

        public NutritionFacts (int servingSize, int servings, optionalFacts) 
        {
            this.servingSize = servingSize;
            this.servings    = servings;
            // code to make defensive copy of optionalFacts
        }
 }

將這些可選參數並將其放置在AbstractMap並將其傳遞給構造函數會不會有問題或不利之處?

我看到的唯一缺點是要對其進行驗證。

  1. 您必須創建一個防御性副本
  2. 創建一個private List<String> validOptionalFacts; 並遍歷AbstractMapkeys ,並確保String值有效,如果無效,則引發異常。
  3. 檢查並為重復的參數引發異常。

對於這個小例子,可以在map外部放置可選參數,但是假設您有10個以上可選參數,這意味着為這些參數創建新的setters/getters ,就像地圖一樣,我可以有這樣的方法:

public NutritionFacts updateParameter(String key, int value){ 
     //call method to validate the key/value
     //update fact
     //return a new object that reflects our change
     return this; 
}

public int retrieveValuefor(String key){
     //call method to validate the key
     //Get value associated with the key
     //return value associated with the key
     return factValue;
}

地圖方法很糟糕,原因如下:

  1. 您的方法與常規的OO編程范例相反。

    • 定義對象時,還定義了可以分配給它的所有可能的屬性,使用該對象的代碼未定義該對象的特征,它只是將對象用於其預期目的。
  2. 該代碼要求使用該對象的任何代碼了解該對象。

  3. 該代碼可讀性較低,更容易出錯,並且很難在多個地方使用。

  4. 該代碼可以在以前不存在的情況下拋出運行時異常(僅這是避免使用該方法的原因)。

如果我想使用由另一個開發人員制作的對象,則只需創建該對象的一個​​實例(或者也許我正在更改已經創建該對象的實例的代碼),然后查看我可以設置和獲取的所有有效屬性。
在此地圖方案下,我是否應該回顧自對象實例化以來發現地圖的所有變更? 如果我想向地圖添加新參數,怎么知道它是否是有效參數? 向下的代碼如何知道此映射中包含哪些神秘參數?
如果您解決此問題的方法是在對象內部定義有效的地圖參數,那么與定義對象的標准方法相反,這樣做的目的是什么?

還有很多原因導致這種方法不受歡迎,但是這種解決方案到底是什么呢? 創建更少的getter和setter? 任何IDE都會自動生成它們,但是即使不是這種情況,對編碼時間的微小改進也永遠都不值得解決方案產生的問題清單。

正如您已經指出的那樣,我認為它的方式除了驗證可能變得更加麻煩之外,還有一些缺點。

正如您對問題的評論所指出的那樣,只有當所有可選參數都具有相同的值時,您的方法才有效。 如果沒有,則必須使用Map<String,Object> 這樣一來,由於丟失了所有類型信息,將使這些參數難以處理。

其次,我認為這是您的方法的主要問題:當使用諸如updateParameter(String key, int value)之類的方法時,有關使用該構建器將要構建的對象所需的參數的知識從該構建器傳輸到客戶端。 相比:

new Builder.updateParameter("calories", 0)
          .updateParameters("fat", 1)
          .updateParameters("carbohydrates",0)
          .build();

new Builder.calories(0)
          .fat(1)
          .carbohydrates(0)
          .build();

使用第二種方法,客戶將知道可以設置碳水化合物,因為建造者為此提供了一種公共方法。 不可能設置參數mumbojumbo ,因為不存在這樣的方法。

在第一種方法中,客戶是否會知道是否還有其他參數proteins 如果您輸錯了怎么辦? 如果所提供的參數實際上未被構建的對象使用,會發生什么? 堅持使用沒有地圖的方法時,所有這些問題甚至都不會擺出姿勢。

總結:您的方法(乍看之下)提供了更多的便利(以安全性,可讀性和可維護性為代價)。

暫無
暫無

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

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