Is this a valid Java implementation of an immutable class and the Builder pattern?

坚强是说给别人听的谎言 提交于 2019-12-05 02:51:23

Generally the class constructed from the Builder doesn't have any specialized knowledge of the builder. That is Immutable would have a constructor to supply the value for foo and bar:

public final class MyImmutable {
  public final int foo;
  public final int bar;
  public MyImmutable(int foo, int bar) {
    this.foo = foo;
    this.bar = bar;
  }
}

The builder would be a separate class:

public class MyImmutableBuilder {
  private int foo;
  private int bar;
  public MyImmutableBuilder foo(int val) { foo = val; return this; }
  public MyImmutableBuilder bar(int val) { bar = val; return this; }
  public MyImmutable build() { return new MyImmutable(foo, bar); }
}

If you wanted, you could add a static method to MyImmutable builder to start from an existing MyImmutable instance:

public static MyImmutableBuilder basedOn(MyImmutable instance) {
  return new MyImmutableBuilder().foo(instance.foo).bar(instance.bar);
}

I've not seen this approach before, but looks like it would work fine.

Basically it makes the builder pattern relatively simple to implement, at the expense of slightly higher runtime overhead (extra objects + cloning operations + a level of indirection in accessor functions that may or may not get compiled out).

A potential variation you might want to consider: if you make the builder objects themselves immutable, you won't need to defensively clone them. This could be an overall win, especially if you build objects a lot more frequently than you change the builders.

Your implementation is similar to the implementation detailed in Josh Bloch's Effective Java 2nd Edition.

One point of contention would be your build() method. If a single builder creates an immutable instance, would it be fair to allow the builder to be used again, considering that it's work has been done? The caution here is that even though you are creating an immutable object, the mutability of your builder may result in a few rather "surprising" bugs.

To correct this, it may be suggested that the build method should create the instance and then make the builder incapable of building the object again, requiring a new builder. Although the boiler-plate may seem tedious, the benefits to be reaped later outweigh the required effort at present. The implementation class can then receive a Builder instance as a constructor parameter, but the builder should then let the instance pull out all it's needed state, releasing the builder instance and preserving final references to the data in question.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!