不变性—在java中创建不可变对象的正确方法

niknxzdl  于 2021-07-11  发布在  Java
关注(0)|答案(1)|浏览(450)

我有以下代码:

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

在这里,我有三节课: SimpleClass , SimpleObservable 以及 SimpleObserver . SimpleClass 在内部使用生成器,我可以创建它的不可变副本,只需使用以下代码更改几个字段:

return builder(this)    //create new immutable object using builder
                .withStrings(strings)   //modify only what changes
                .withSimpleObservable(simpleObservable.changeCanChange(strings))
                .build();

我怎样才能在其他两个类中使用 final 领域?目前我不使用最终的,复制构造函数的作品。

SimpleObserver o = new SimpleObserver(this);
        o.name = changed.get(0); //if name is final, I could not do this
        return o;

有什么选择吗 final 字段,并保持创建新的不可变类的能力,而更改的属性很少?

46scxncf

46scxncf1#

我想没有比这更简单的方法了(lombok),但这不是java,所以。。。

@Builder(toBuilder = true)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
final class SimpleObservable{
    private final SimpleObserver observer;
    private final List<String> canChange;

    public SimpleObservable(List<String> canChangeSet){
        canChange = new ArrayList<>(canChangeSet);
        observer = SimpleObserver.builder()
                .name(canChangeSet.get(0))
                .build();
    }

    public SimpleObservable changeCanChange(List<String> canChangeSet){
        SimpleObservableBuilder sob = this.toBuilder();
        sob.canChange(new ArrayList<>(canChangeSet));
        sob.observer(observer.notifyMe(sob.canChange));
        return sob.build();
    }
}

@Builder(toBuilder = true)
final class SimpleObserver{
    private final String name;

    public SimpleObserver notifyMe(List<String> changed){
        SimpleObserverBuilder sob = this.toBuilder();
        sob.name(changed.get(0));
        return sob.build();
    }
}

相关问题