2

I have an immutable class that looks something like this:

final class Foo {
  private final String name;
  private final MutableObject mo;

  public Foo(String name, MutableObject mo) {
    mo = mo.clone();
    if(!Foo.testValidity(mo)) // this test is very expensive
      throw new IllegalArgumentException();

    this.name = name;
    this.mo = mo;
  }

  public Foo bar(Foo that) {
    return new Foo(this.name, that.mo);
  }
}

The bar method returns a Foo object by mixing the internals of two existing Foo objects. Because the MutableObject is already in a Foo object, it is guaranteed to be valid and doesn't need copying or verification (which the constructor currently does).

Because the verification (and possibly the clone?) are expensive, I'd like to avoid them if possible. What's the best way to do this? This is was what I came up with:

final class Foo {
  private final String name;
  private final MutableObject mo;

  public Foo(String name, MutableObject mo) {
    this(name, mo, VerificationStyle.STRICT);
  }

  private Foo(String name, MutableObject mo, VerificationStyle vs) {
    if(vs == VerificationStyle.STRICT) {
      mo = mo.clone();
      if(!Foo.testValidity(mo)) // this test is very expensive
        throw new IllegalArgumentException();
    }

    this.name = name;
    this.mo = mo;
  }

  public Foo bar(Foo that) {
    return new Foo(this.name, that.mo, VerificationStyle.LENIENT);
  }

  private static enum VerificationStyle { STRICT, LENIENT; }
}

I thought that, at least, it would be cleaner/clearer than using a dummy parameter and less error prone than swapping the order, but is there a better way to do this? How would this normally be accomplished?

Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121
Kevin
  • 1,870
  • 2
  • 20
  • 22
  • 1
    I will still stick to your first approach, it looks simpler. And to meet you requirement of skipping the `testing of mo` I would prefer to add a field, say `isValid`with default value of `false`, in the `mo` object and would set it to `true` once the `testValidity`method is invoked for the first time. And the subsequent invocations of `testValidity` methods would first check this `isValid` flag and will continue the test only if `isValid` is `false`. – Madhusudana Reddy Sunnapu Feb 09 '16 at 03:28

1 Answers1

1

Maybe hide the constructor altogether and create new instances using a factory-like method, e.g.:

  private Foo(String name, MutableObject mo) {
    this.name = name;
    this.mo = mo;
  }
  public Foo bar(Foo that) {
    return new Foo(this.name, that.mo);
  }
  public static Foo create(String name, MutableObject mo) {
    mo = mo.clone();
    if(!Foo.testValidity(mo)) // this test is very expensive
      throw new IllegalArgumentException();
    return new Foo(name, mo);
  }
radoh
  • 4,554
  • 5
  • 30
  • 45