When I want to make an immutable type with a lot of attributes. I
generally like to use a static inner class as a builder object.
Here's an example with just two attributes.
public final class Person{
private final String firstName;
private final String lastName;
public Person(String firstName, String lastName){
super();
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName(){return firstName;}
public String getLastName(){return lastName;}
public static class Builder {
private String firstName;
private String lastName;
public Builder setFirstName(String firstName){
this.firstName = firstName;
return this;
}
public Builder setLastName(String lastName){
this.lastName = lastName;
return this;
}
public Person newPerson(){
return new Person(firstName, lastName);
}
}
}
Then in my client code, I would do:
Person keith = new Person.Builder().setFirstName
("Keith").setLastName("Haber").newPerson();
Or if I need to instantiate a lot of similar objects, I can hang on to
my Builder object. (Could be handy for constructing relatives, I
suppose.)
A nice thing about this approach is that I get the benefit of readable
setters instead of working with long lists of meticulously ordered
constructor arguments (not so big a deal with two attributes, but very
helpful when working with six or more attributes), but my immutable
objects don't have setters at all.
And by making the builder class a static inner class, it's obvious
which builder classes go with which immutable types -- it's always
named <immutable type name>.Builder.
In episode 219 they talked about objects having a "construct phase"
with setters and a "use phase" when the object construction is
"finished." To my mind this approach is reasonably close to that
idea.
Keith
On Dec 3, 10:58 pm, hlovatt <[EMAIL PROTECTED]> wrote:
> In 219 there was a long discussion about setting up an object and then
> making it immutable. There are a couple of ways of doing this in Java
> already:
>
> public class FooArgs {
> public int x = 1; // 1 is default
> public int y = 2;
> public int z = 3;
> ...
>
> }
>
> public class Foo {
> public Foo( FooArgs args ) { ... }
> ...
>
> }
>
> Foo foo = new Foo( new FooArgs() {{ x = 2 }} );
>
> Another option is an immutable and mutable versions that inherit from
> a common base and implement a standard conversion interface. First the
> standard interface:
>
> public interface ImmutableValueConversions {
> Immutable toImmutable() throws IllegalStateException;
> Value toValue();
>
> }
>
> Below is an integer example that uses an abstract class as the base of
> the hierarchy. You can also use interfaces. The abstract class is:
>
> 8:public abstract class AbstractInteger extends AbstractValue
> 9: implements ImmutableValueConversions, InstanceFactory {
> 10: public abstract int getValue();
> 11:
> 12: public abstract AbstractInteger instanceOfSelf( int value );
> 13:
> 14: public AbstractInteger add( final int rhs ) {
> 15: return instanceOfSelf( getValue() + rhs );
> 16: }
> 17:}
>
> Then the immutable version:
>
> 9:public final class ImmutableInteger2 extends AbstractInteger
> 10: implements Immutable {
> 11: private final int value;
> 12:
> 13: public ImmutableInteger2( final int value ) {
> 14: this.value = value;
> 15: }
> 16:
> 17: public int getValue() {
> 18: return value;
> 19: }
> 20:
> 21: public Immutable toImmutable() {
> 22: return this;
> 23: }
> 24:
> 25: public Value toValue() {
> 26: return new ValueInteger( value );
> 27: }
> 28:
> 29: public AbstractInteger instanceOfSelf( final int value ) {
> 30: return new ImmutableInteger2( value );
> 31: }
> 38:}
>
> And the value version:
>
> 9:public final class ValueInteger extends AbstractInteger {
> 10: // Not final, this is the value version
> 11: private int value;
> 12:
> 13: public ValueInteger( final int value ) {
> 14: this.value = value;
> 15: }
> 16:
> 17: public int getValue() {
> 18: return value;
> 19: }
> 20:
> 21: // Setter, this is the value version!
> 22: public void setValue( final int value ) {
> 23: this.value = value;
> 24: }
> 25:
> 26: public Immutable toImmutable() {
> 27: return new ImmutableInteger2( value );
> 28: }
> 29:
> 30: public Value toValue() {
> 31: return new ValueInteger( value );
> 32: }
> 33:
> 34: public AbstractInteger instanceOfSelf( final int value ) {
> 35: return new ValueInteger( value );
> 36: }
> 37:
> 38: // Set and add combined (+=), this is the value version!
> 39: public ValueInteger setAdd( final int rhs ) {
> 40: value += rhs;
> 41: return this;
> 42: }
> 49:}
>
> Then you can use these classes like this:
>
> ImmutableInteger i = (ImmutableInteger)( new ValueInteger().setValue
> ( 2 ).toValue() );
>
> My own pet project, PEC, is an extensible compiler that can enforce
> patterns, the above immutable pattern can be enforced. More details
> from:
>
> http://pec.dev.java.net/nonav/frontpage.html
>
> What do others do?
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "The
Java Posse" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/javaposse?hl=en
-~----------~----~----~----~------~----~------~--~---