Design pattern review: freeze/thaw (aka, "reversible builder" pattern) OK, this question may seem a little strange at first; however I'd like to have your comments on it.

Background: I do Java. A lot. Java is a statically typed language, it has means to restrict visibility of instance variables, etc. And as such the builder pattern (see here) is quite adapted to it.

I took this pattern a step further. The builder pattern is a one-step process: once you .build(), you obtain an instance, preferrably immutable; but once you have the instance, there is no going back. The freeze/thaw pattern is a "reversible builder".

I implemented it in Java and this gives the following interfaces, which I use quite a lot in my own projects (one-sided discussion about this pattern here):

// Frozen
@Immutable
public interface Frozen&lt;T extends Thawed&lt;? extends Frozen&lt;T&gt;&gt;&gt;
{
    /**
     * Return a thawed representation of this frozen object.
     *
     * @return a thawed object
     */
    T thaw();
}

// Thawed
@NotThreadSafe
public interface Thawed&lt;F extends Frozen&lt;? extends Thawed&lt;F&gt;&gt;&gt;
{
    /**
     * Obtain a frozen representation of this thawed object
     *
     * @return a frozen, immutable object
     */
    F freeze();
}


This pattern means that if you have a frozen instance f, you can obtained a thawed instance of that instance by calling .thaw(), modify it (since .thaw() returns a builder) and freeze it again:

// In java, again
final F newFrozen = frozen.thaw().setX().setY().etc().freeze();


I view this pattern as beneficial for several reasons:


thawing an instance gives you a builder with that instance's full state (and you can thaw as many times as you want, in a thread safe manner since frozen instances are immutable by contract);
you get all the power of builders on the thawed side.


I use this pattern a lot; I find it useful. Do you? What would be your gripes against it?

Sample implementation of a simple pair:

public final class MyClass
    implements Frozen&lt;Builder&gt;
{
    final int value;

    private MyClass(final Builder builder)
    {
        value = builder.value;
    }

    public static Builder newBuilder()
    {
        return new Builder();
    }

    public int getValue()
    {
        return value;
    }

    @Override
    public Builder thaw()
    {
        return new Builder(this);
    }

    public static final class Builder
        implements Thawed&lt;MyClass&gt;
    {
        private int value;

        private Builder()
        {
        }

        private Builder(final MyClass myClass)
        {
            value = myClass.value;
        }

        public Builder withValue(final int value)
        {
            this.value = value;
        }

        @Override
        public MyClass freeze()
        {
            return new MyClass(this);
        }
    }
}


For more complex cases, I generally create both classes in the same package and make instance variables for both package visible (this leaves of course the responsibility on me that what I inject into the frozen part is actually immutable, but I deal with it ;)

EDIT Right now the methods are called .thaw() and .freeze(), to reflect the pattern's intents; do you think of better names?

EDIT 2 Objections from @bowmore: the SRP (Single Responsibility Principle) is violated; this is true: the frozen instance has the added responsibility that it must generate a pre-filled thawed instance. The suggestion here is to create an additional constructor/static factory method/method (pick your poison) on the builder class so that it be able to "swallow" the contents of the frozen instance.
Pattern pros and cons :

Pros :


easy to use
readable (provided you are familiar with the pattern)


Cons :


forces a cyclic dependency between builder and the class being built (we're probably not crossing package boundaries, though)
moves part of the responsibility of the builder to the class being built, in addition to the responsibility that class already had (violating the SRP)


General remarks :


I see no potential clients for the interfaces, i.e. they are little more than marker interfaces.


Conclusion :

In my opinion the pattern adds too little value for what it trades off.