构造方法参数过多的解决方法
提出问题:
例如:食品影响成分标签
- 必需的属性——每次建议的摄入量,每罐的份量和每份卡路里,
- 以及超过20 个可选的属性——总脂肪、饱和脂肪、反式脂肪、胆固醇、钠等等。
大多数产品只有这些可选字段中的少数, 且具有非零值。
应该为这样的类编写什么样的构造方法或静态工厂?
1. 可伸缩构造方法模式(Telescoping constructor pattern)
在这种模式中,
首先提供一个只有必需参数的构造方法,
接着提供增加了一个可选参数的构造函数,
然后提供增加了两个可选参数的构造函数,等等,
最终在构造函数中包含所有必需和可选参数。
以下就是它在实践中的样子。为了简便起⻅,只显示了四个可选属性:
// Telescoping constructor pattern - does not scale well!
public class NutritionFacts {
private final int servingSize; // (mL) required
private final int servings; // (per container) required
private final int calories; // (per serving) optional
private final int fat; // (g/serving) optional
private final int sodium; // (mg/serving) optional
private final int carbohydrate; // (g/serving) 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;
}
/**
可以使用,包含所有要设置的参数的,最短参数列表的,构造方法来创建对象
**/
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
}
}
缺点:
1、参数扩展性差,随着参数数量的增加,代码维护成本大大增加;
2、增加使用复杂性,难以理解,参数过多时必须仔细对比参数顺序。
2. JavaBeans 模式
当在构造方法中遇到许多可选参数时,另一种选择是 JavaBeans 模式,在这种模式中,调用一个无参的构造方法来创建对象,然后调用 setter 方法来设置每个必需的参数和可选参数:
// JavaBeans Pattern - allows inconsistency, mandates mutability (pages 11-12)
public class NutritionFacts {
// Parameters initialized to default values (if any)
private int servingSize = -1; // Required; no default value
private int servings = -1; // Required; no default value
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public NutritionFacts() { }
// Setters
public void setServingSize(int val) { servingSize = val; }
public void setServings(int val) { servings = val; }
public void setCalories(int val) { calories = val; }
public void setFat(int val) { fat = val; }
public void setSodium(int val) { sodium = val; }
public void setCarbohydrate(int val) { carbohydrate = val; }
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
}
}
优点:
这种模式没有伸缩构造方法模式的缺点,易于理解。
缺点:
破坏了类的不可变性,需要程序员增加工作以确保线程安全。
不可变类简单来说是它的实例不能被修改的类。包含在每个实例中的所有信息在对象的生命周期中是固定的。