[Effective Java] Article 2: Consider using a constructor with multiple constructor parameters

Neither constructors nor static factory methods 1 handle multiple parameters well.

For example, there is a class for the Nutrition Facts labels that appear on the outside of packaged foods. These labels contain the required ingredients: content per serving, content per can, and calories per serving, as well as some other optional displays such as total fat, Saturated fat mass, converted fat, cholesterol, sodium, and more.

public class NutritionFacts {

  /** 必须参数*/
  private int servingSize;

  /** 必须参数*/
  private int servings;

  /** 非必须*/
  private int calories;

  /** 非必须*/
  private int fat;

  /** 非必须*/
  private int sodium;

  /** 非必须*/
  private int carbohydrate;

}

Just imagine, constructing the constructor of this class, using constructors and static factory methods are not very well understood. Due to too many parameters, you may divide it into several constructors (overlapping constructors), or use JavaBeans to build, or use the constructor pattern described in this article.

Overlapping Constructor Pattern

First provide a constructor consisting of required parameters, and then add a non-required parameter to form a constructor. The implementation is as follows:

public class NutritionFacts {

  /** 必须参数*/
  private int servingSize;

  /** 必须参数*/
  private int servings;

  /** 非必须*/
  private int calories;

  /** 非必须*/
  private int fat;

  /** 非必须*/
  private int sodium;

  /** 非必须*/
  private int carbohydrate;

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

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

  public NutritionFacts(int servingSize, int servings, int calories, int fat) {
    this.servingSize = servingSize;
    this.servings = servings;
    this.calories = calories;
    this.fat = fat;
  }

  public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium) {
    this.servingSize = servingSize;
    this.servings = servings;
    this.calories = calories;
    this.fat = fat;
    this.sodium = sodium;
  }

  public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium,
      int carbohydrate) {
    this.servingSize = servingSize;
    this.servings = servings;
    this.calories = calories;
    this.fat = fat;
    this.sodium = sodium;
    this.carbohydrate = carbohydrate;
  }
}

The disadvantage is also obvious. When there are enough parameters, the caller may need to refer to the constructor to map the parameters one by one. In case the constructor changes the order of the parameters, the caller will have to make changes as well.

JavaBeanstructure

Provide a default constructor and then take a setmethod to set it. code show as below:

public class NutritionFacts {

  /** 必须参数*/
  private int servingSize;

  /** 必须参数*/
  private int servings;

  /** 非必须*/
  private int calories;

  /** 非必须*/
  private int fat;

  /** 非必须*/
  private int sodium;

  /** 非必须*/
  private int carbohydrate;

  //Getter & Setter
}

public class NutritionFactsDemo {

  public static void main(String[] args) {
    NutritionFacts nutritionFacts = new NutritionFacts();
    nutritionFacts.setServings(100);
    nutritionFacts.setServingSize(10);
  }

}

JavaBeanIt has serious shortcomings. First, because the construction of objects is carried out in steps, Beanit may not be in a consistent state; second, in a multi-threaded environment, developers need to ensure the thread safety of constructing objects.

Construction mode (recommended)

Unlike the previous two methods, the construction mode first builds builderthe object with required parameters, then buildercalls a similar settermethod on the object for non-required parameters, and finally calls the buildmethod without parameters to generate the object.

public class NutritionFacts {

  /** 必须参数*/
  private int servingSize;

  /** 必须参数*/
  private int servings;

  /** 非必须*/
  private int calories;

  /** 非必须*/
  private int fat;

  /** 非必须*/
  private int sodium;

  /** 非必须*/
  private int carbohydrate;

  private NutritionFacts(Builder builder) {
    this.servingSize = builder.getServingSize();
    this.servings = builder.getServings();
    this.calories = builder.getCalories();
    this.fat = builder.getFat();
    this.sodium = builder.getSodium();
    this.carbohydrate = builder.getCarbohydrate();
  }


  public static final class Builder {

    /** 必须参数*/
    private int servingSize;

    /** 必须参数*/
    private int servings;

    private int calories;
    private int fat;
    private int sodium;
    private int carbohydrate;

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

    public static Builder newInstance(int servingSize, int servings) {
      return new Builder(servingSize, servings);
    }

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

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

    public Builder calories(int calories) {
      this.calories = calories;
      return this;
    }

    public Builder fat(int fat) {
      this.fat = fat;
      return this;
    }

    public Builder sodium(int sodium) {
      this.sodium = sodium;
      return this;
    }

    public Builder carbohydrate(int carbohydrate) {
      this.carbohydrate = carbohydrate;
      return this;
    }

    // Getter & Setter

    public NutritionFacts build() {
      return new NutritionFacts(this);
    }
  }
}

The constructor pattern is not without its shortcomings, the disadvantage is that there is a lot of code. However, for multi-parameter construction, especially in actual development, it is strongly recommended to use the constructor pattern.

More long-winded, you can search Intellij ideain plugin 2builder , and you can use this plugin to directly generate the code of the constructor mode.

Extended reading

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325950175&siteId=291194637