简体   繁体   中英

How to update a field in a immutable object

Supposing the following class:

@Immutable
public final MyMessageClass {

 private String message;
 private Date dateLastChange;
 private String identifier;

 public MyClass(final String message){
   this.message = message;
   dataLastChange = new Date();
 } 

 public Date lastChange() {
   return new Date(dateLastChange.getTime());
 }

 public String messageValue(){
   return message;
 }

}

Once we have built an object of this class,

MyMessageClass myMessageObject = new MyMessageClass("Once upon a time ...");

and once we have finish doing some operations with it,

 logger.info("The message is{}",myMessageObject.messageValue());
 logger.info("The last change was done on {}",myMessageObject.lastChange());

it is expected to get an identifier from somewhere (a remote service, for instance) and attach it to the message . But, if I do something like this:

myMessageObject.setIdentifier(identifier);

I supposedly breaking the immutability capability of the object. If so, how is the best way to update the identifier field avoiding to do a new constructor call (so creating a new object)?

So the problem is just because you want to log some stuff first? Can't you do that after you've constructed the object?

Alternatively, you can use the builder pattern, with something like this. Note the final instance fields - instances of this class will be immutable even without the annotation.

@Immutable
public final MyMessageClass {

    private final String message;
    private final Date dateLastChange;
    private final String identifier;

    public MyClass(final MyMessageClass.Builder builder){
        this.message = builder.message;
        this.dataLastChange = builder.dataLastChange;
        this.identifier = builder.identifier;
    } 

    public Date lastChange() {
        return new Date(dateLastChange.getTime());
    }

    public String messageValue(){
        return message;
    }

    public String identifier(){
        return identifier;
    }

    public static final class Builder {
        private String message;
        private final Date dateLastChange = new Date();
        private String identifier;

        public Builder message(final String message) {
            this.message = message;
            return this;
        }

        public String message() {
            return message;
        }

        public Builder identifier(final String identifier) {
            this.identifier = identifier;
            return this;
        }

        public String identifier() {
            return identifier;
        }

        public Date lastChange() {
            return new Date(dateLastChange.getTime());
        }

        public MyMessageClass build() {
            return new MyMessageClass(this);
        }
    }
}

You can then incrementally build the content of your object.

MyMessageClass.Builder builder = new MyMessageClass.Builder().message("Once upon a time ...");
logger.info("The message is{}", builder.message());
logger.info("The last change was done on {}",builder.lastChange());
String identifier = // get the identifier from somewhere
MyMessageClass message = builder.identifier(identifier).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