I have following code:
package me.immutable;
import java.util.*;
public class Immutable {
public static void main(String[] args) {
//this is immutable using builder
SimpleClass wb = new SimpleClass.Builder()
.addString("a")
.addString("b")
.addString("c")
.withWillNotChange("notchange")
.build();
//this is new immutable with changes only needed properties
//wb object remains unchanged
SimpleClass newWb = wb.withDifferentStrings(Arrays.asList("d", "e", "f"));
}
}
class SimpleClass {
private final List<String> strings;
private final SimpleObservable simpleObservable;
private final String willNotChange;
private SimpleClass(Builder builder){
this.strings = builder.strings;
this.willNotChange = builder.willNotChange;
this.simpleObservable =
builder.simpleObservable == null ?
new SimpleObservable(strings) :
builder.simpleObservable;
}
SimpleClass withDifferentStrings(List<String> strings){
return builder(this) //create new immutable object using builder
.withStrings(strings) //modify only what changes
.withSimpleObservable(simpleObservable.changeCanChange(strings))
.build();
}
Builder builder(SimpleClass sc){
return new Builder(sc);
}
static class Builder{
private List<String> strings = new ArrayList<>();
private SimpleObservable simpleObservable;
private String willNotChange;
Builder(){}
Builder(SimpleClass sc){
this.strings = sc.strings;
this.willNotChange = sc.willNotChange;
this.simpleObservable = sc.simpleObservable;
}
Builder addString(String s){
strings.add(s);
return this;
}
Builder withWillNotChange(String s){
willNotChange = s;
return this;
}
Builder withStrings(List<String> strings){
this.strings = strings;
return this;
}
private Builder withSimpleObservable(SimpleObservable simpleObservable){
this.simpleObservable = simpleObservable;
return this;
}
SimpleClass build(){
return new SimpleClass(this);
}
}
}
class SimpleObservable{
private SimpleObserver observer;
private List<String> canChange = new ArrayList<>();
public SimpleObservable(List<String> canChangeSet){
canChange.addAll(canChangeSet);
observer = new SimpleObserver(canChange);
}
private SimpleObservable(SimpleObservable so){
canChange = so.canChange;
observer = so.observer;
}
public SimpleObservable changeCanChange(List<String> canChangeSet){
//No builder so we use copy constructor to build new immutable object and not change this one
SimpleObservable o = new SimpleObservable(this);
o.canChange = canChangeSet; //update only what changes
o.observer = observer.notifyMe(o.canChange);
return o;
}
}
class SimpleObserver{
private String name;
public SimpleObserver(List<String> canChange){
this.name = canChange.get(0);
}
private SimpleObserver(SimpleObserver so){
name = so.name;
}
public SimpleObserver notifyMe(List<String> changed){
SimpleObserver o = new SimpleObserver(this);
o.name = changed.get(0);
return o;
}
}
Here, I'm having 3 classes: SimpleClass
, SimpleObservable
and SimpleObserver
.
SimpleClass
is using builder inside and I can create immutable copy of it with changing only few fields using following code:
return builder(this) //create new immutable object using builder
.withStrings(strings) //modify only what changes
.withSimpleObservable(simpleObservable.changeCanChange(strings))
.build();
How could I do something similar in other two classes with using final
fields? Currently I do not use final's, and copy-constructor works.
SimpleObserver o = new SimpleObserver(this);
o.name = changed.get(0); //if name is final, I could not do this
return o;
Is there some option to have final
fields, and keep ability to create new immutable classes with changing few properties?