开发者

Is there a way to ensure at compile time that certain fields in an immutable object are set whilst keeping role of the arguments clear?

I'm experimenting with ways of creating immutable objects. The following builder objects are quite attractive because they keep the role of the arguments clear. However I would like to use the compiler to verify that certain fields are set, like with the Immutable() constructor invocation. StrictImmutableBuilder provides those checks, but is rather noisy. Is there some way to get the same checks but with the form of LaxImmutableBuilder开发者_如何学编程? Perhaps using annotations?

public class Immutable {

    public static void main(String[] args) {

        new Immutable("13272873C", 23, false);
        // nice but what where those arguments?

        new LaxImmutableBuilder() {{
            refCode("13272873C");
            age(23);
            subscribed(false);
        }}.build();
        // now I know what each value represents
        // but what if I forgot to set one?

        new StrictImmutableBuilder() {
            public String refCode() { return "13272873C"; }

            public int age() { return 23; }

            public boolean subscribed() { return false; }
        }.build();
        // now I'm forced to set each field, but now 
        // we have the extra noise of "return"
        // and also "public" if we want to use
        // this outside the current package

        // is there another way? maybe using annotations?
    }

    private final String refCode;
    private final int age;
    private final boolean subscribed;

    public String getRefCode() {
        return refCode;
    }

    public int getAge() {
        return age;
    }

    public boolean isSubscribed() {
        return subscribed;
    }

    public Immutable(String a, int b, boolean c) {
        this.refCode = a;
        this.age = b;
        this.subscribed = c;
    }

}

abstract class StrictImmutableBuilder {
    public abstract String refCode();

    public abstract int age();

    public abstract boolean subscribed();

    public Immutable build() {
        return new Immutable(refCode(), age(), subscribed());
    }
}

abstract class LaxImmutableBuilder {

    private String refCode;
    private int age;
    private boolean subscribed;

    protected void refCode(String refCode) {
        this.refCode = refCode;
    }

    protected void age(int age) {
        this.age = age;
    }

    protected void subscribed(boolean subscribed) {
        this.subscribed = subscribed;
    }

    public Immutable build() {
        return new Immutable(refCode, age, subscribed);
    }

}


Here's the pattern I use:

class YourClass {
  // these are final
  private final int x;
  private final int y;

  private int a;
  private int b;

  // finals are passed into the constructor
  private YourClass(int x, int y) {
    this.x = x;
    this.y = y;
  }

  public static class Builder {
    // int x, int y, int a, int b
    // whatever's final is passed into constructor
    public Builder(int x, int y) {
      this.x = x;
      this.y = y;
    }
    // a and b are optional, so have with() methods for these
    public Builder withA(int a) {
      this.a = a;
      return this;
    }
    public Builder withB(int b) {
      this.b = b;
      return this;
    }
    public YourClass build() {
      YourClass c = new YourClass (x, y);
      c.a = a;
      c.b = b;
      return c;
    }
  }
}


there is this trick: Type-safe Builder Pattern

http://michid.wordpress.com/2008/08/13/type-safe-builder-pattern-in-java/

but that's just too crazy.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜