将可变对象转换为不可变对象 [英] convert a mutable object to an immutable object

查看:54
本文介绍了将可变对象转换为不可变对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使bean不可变,而传统的方法是使所有字段final并在构造函数中设置其值.

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.

我想做的是创建一个可变的bean实例,一旦它完全填充,我想烘焙"它,即使其不可变.

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.

是否有一种方法可以在运行时将实例从non-final更改为final,而无需子类化等.

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

我敢肯定,仅使用标准的java/reflection不能做到这一点,但我怀疑使用某些字节码更改(例如javassist之类)可能是可行的.

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在他的《有效Java,第二版》 一书的第二章创建和销毁Java"中解决了这个问题.对象." 您可以在此处查看从他的书中摘录的示例:

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;
    }
}

使用此对象的示例是:

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();

这篇关于将可变对象转换为不可变对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆