当一个类中的部分参数可选,部分参数必填的时候,我们会如何写这个类呢
使用构建器
public class NutritionFacts {
private final int servingSize; // require
private final int servings; // require
private final int calories; // optional
private final int fat; // optional
private final int sodium; // optional
private final int carbohydrate; // optional
public NutritionFacts(int servingSize, int servings) {
this(servingSize,servings,0);
}
public NutritionFacts(int servingSize, int servings, int calories) {
this(servingSize,servings,calories,0);
}
public NutritionFacts(int servingSize, int servings, int calories, int fat) {
this(servingSize,servings,calories,fat,0);
}
public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium) {
this(servingSize,servings,calories,fat,sodium,0);
}
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;
}
}
NutritionFacts cocaCola = new NutritionFacts(240,8,100,0,35,27);
构造器调用会使用很多我们根本不会用到的参数,但是还是不得不用,这里时全部设置成了0,仅仅是这6个参数看起来还不算太惨,但是参数越多,意味着构造器越多,这个类逐渐变的臃肿不堪
重叠构造器模式可行,但是有许多参数的时候,客户端代码很难编写,并且仍然较难以阅读
javaBean模式
public class NutritionFacts {
private int servingSize = -1; // require
private int servings = -1; // require
private int calories = 0; // optional
private int fat = 0; // optional
private int sodium = 0; // optional
private int carbohydrate = 0; // optional
public NutritionFacts() {
}
public int getServingSize() {
return servingSize;
}
public void setServingSize(int servingSize) {
this.servingSize = servingSize;
}
public int getServings() {
return servings;
}
public void setServings(int servings) {
this.servings = servings;
}
public int getCalories() {
return calories;
}
public void setCalories(int calories) {
this.calories = calories;
}
public int getFat() {
return fat;
}
public void setFat(int fat) {
this.fat = fat;
}
public int getSodium() {
return sodium;
}
public void setSodium(int sodium) {
this.sodium = sodium;
}
public int getCarbohydrate() {
return carbohydrate;
}
public void setCarbohydrate(int carbohydrate) {
this.carbohydrate = carbohydrate;
}
}
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
使用javaBean创建实例很容易,代码阅读起来也很容易
但是缺点也十分明显,在类参数设置之前该类已经可以使用了,也就说如果你少了某个参数的话并不会影响什么,但是确实影响到了业务逻辑了,这在多线程上更加明显.说简单点的话,就是如果你少了某项参数没设置(或者你忘了),那依然能执行下去,但是结果可想而知
第二个缺点是,如果对象中含有final修饰的变量,那么是不能set的
builder模式
package com.chapter2;
public class NutritionFacts {
private final int servingSize; // require
private final int servings; // require
private final int calories; // optional
private final int fat; // optional
private final int sodium; // optional
private final int carbohydrate; // optional
public NutritionFacts(Builder builder) {
this.servingSize = builder.servingSize;
this.servings = builder.servings;
this.calories = builder.calories;
this.fat = builder.fat;
this.sodium = builder.sodium;
this.carbohydrate = builder.carbohydrate;
}
public static class Builder {
private int servingSize; // require
private int servings; // require
private int calories = 0; // optional
private int fat = 0; // optional
private int sodium = 0; // optional
private int carbohydrate = 0; // optional
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
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 NutritionFacts build() {
return new NutritionFacts(this);
}
}
}
NutritionFacts cocaCola = new Builder(240,8).sodium(10).build();
这样代码很容易编写,灵活并且又易于阅读,算是兼顾了以上的两种优点
我们可以使用泛型来创建builder抽象工厂
public interface Builder {
public T build();
}
public class NutritionFactsBuilder implements Builder {
private int servingSize; // require
private int servings; // require
private int calories = 0; // optional
private int fat = 0; // optional
private int sodium = 0; // optional
private int carbohydrate = 0; // optional
public int getServingSize() {
return servingSize;
}
public int getServings() {
return servings;
}
public int getCalories() {
return calories;
}
public int getFat() {
return fat;
}
public int getSodium() {
return sodium;
}
public int getCarbohydrate() {
return carbohydrate;
}
public NutritionFactsBuilder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
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;
}
@Override
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
public class NutritionFacts {
private final int servingSize; // require
private final int servings; // require
private final int calories; // optional
private final int fat; // optional
private final int sodium; // optional
private final int carbohydrate; // optional
public NutritionFacts(NutritionFactsBuilder 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();
}
}
builder的不足
builder的不足点是你想要得到目标对象的前提是你得先实例化builder对象,这回带来性能上的差异
我个人的理解: builder方法仅仅只能在工具类的地方使用,不然进行一些变种也是可以的,对于我现在来说 实体对象必不可少的有get和set方法.
总结
如果类的构造器或者静态工厂中具有对个参数,设计这种类的时,Builder模式就是种不错的选择.