我想使bean不可变,传统的方法是创建所有字段final
并在构造函数中设置它们的值。
在我看来,这很有效,除非有许多字段需要通过一些复杂的逻辑相互依赖地计算,或者当多个服务需要参与设置值时。
工厂是另一种方法,但我无法想出一个避免过多代码的整洁模型。
我想要做的是创建一个bean的可变实例,一旦它被完全填充,我想“烘焙”它,即使它变得不可变。
有没有办法在运行时将实例更改为从non-final
更改为final
而不进行子类化等。
我很确定它不能仅使用标准的java /反射来完成,但我怀疑它可能使用一些字节码改变,例如javassist等。
一个漂亮整洁的工厂模式也可能会得到这个标记......
答案 0 :(得分:2)
Joshua Bloch在他的书“ Effective Java,Second Edition ”的第二章“创建和销毁Java对象”中解决了这个问题。 You can view an example taken from his book here:
// Builder Pattern public class NutritionFacts { private final int servingSize; private final int servings; private final int calories; private final int fat; private final int sodium; private final int carbohydrate; 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 Builder calories(int val) { calories = val; return this; } public Builder fat(int val) { fat = val; return this; } public Builder carbohydrate(int val) { carbohydrate = val; return this; } public Builder sodium(int val) { sodium = val; return this; } public NutritionFacts build() { return new NutritionFacts(this); } } private NutritionFacts(Builder builder) { servingSize = builder.servingSize; servings = builder.servings; calories = builder.calories; fat = builder.fat; sodium = builder.sodium; carbohydrate = builder.carbohydrate; } }
使用此对象的示例是:
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).carbohydrate(27).build();
从上面的示例中可以看出,您可以在将可变对象构建为不可变对象之前先创建它。还可以调整对象的构建器并重新使用它来生成多个不可变对象。例如:
NutritionFacts.Builder food = new NutritionFacts.Builder(1, 1);
NutritionFacts salad = food.calories(100).build();
NutritionFacts bigMac = food.calories(1000).build();