简体   繁体   中英

convert a mutable object to an immutable object

I'd like to make a bean immutable and the traditional approach is to make all fields final and set their values in the constructor.

In my opinion this works well, unless there are many fields which need to be calculated interdependently via some complex logic or when multiple services need to take part in setting values.

A factory is another approach but I can't come up with a tidy model that avoids too much code.

What I'd like to do is create a mutable instance of the bean and once it is completely populated, I would like to "bake" it, ie make it immutable.

Is there a way to alter the instance at runtime changing fields from non-final to final without subclassing etc.

I'm fairly certain it can't be done just using standard java/reflection but I suspect it might be possible using some byte-code alteration such as javassist or the like.

A nice tidy factory pattern might get the tick too...

Joshua Bloch has addressed this problem in his book, Effective Java, Second Edition , in the second chapter on "Creating and Destroying Java Objects." 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; } }

An example to use this object is:

NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).carbohydrate(27).build();

As you can see from the above example, you can create a mutable object first before building it into an immutable object. The object's builder can also be adjusted and re-used to produce multiple, immutable objects. For example:

NutritionFacts.Builder food = new NutritionFacts.Builder(1, 1);
NutritionFacts salad = food.calories(100).build();
NutritionFacts bigMac = food.calories(1000).build();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM