Stan - thanks for the clarification. The ImmutableDTO(MutableDTO) constructor seems fairly obvious in retrospect, but somehow I was thinking you meant something else. Never mind. It's certainly one of the possible ways to go from mutable to immutable object, and not a bad one. I tend to avoid calling constructors directly in many of my classes, preferring factory methods of one sort or another. But that's a minor difference - it wouldn't be hard to replace your constructor above with ImmutableDTO.createFrom(MutableDTO) method. Either way there's another minor tedious bit I'd like to avoid, where you have to write a copy constructor or something similar, transferring all values from the MutableDTO to the ImmutableDTO.
[Stan]: I like your notion that the mutable object is a factory or somehow renders itself as the immutable one. Makes the immutable one have no dependence on the mutable one. Would the mutable one use a bunch of protected or package scope setters to load the immutable? Well, I tend to favor making the mutable Builder a nested class inside the class it's supposed to build. That way it has direct access to the private variables of the top-level class. In reality this is implemented with package-access synthetic mutator methods. But as long as I don't have to write them or look at them, I'm happy.
[Stan]: There's nothing to prevent anyone from using the mutable one. Maybe it has no public getters which would make it useless outside the package? Yeah, I go back and forth over which of those I prefer. Consider String vs. StringBuilder - neither is a subtype of the other. You can write a method that requires a String parameter, and you will get an immutable String, period. Whether it was originally constructed with a StringBuilder is irrelevant. Or, you can write a method which takes a CharSequence parameter, which may be a String, or StringBuilder, or something else. In general one might think it's good to write to the more general interface, but not always.
Here is a recent example of how that can cause confusion. That's one of the reasons I like immutable types where possible.
Here's an idea I had for making a reasonably simple mutable Builder / immutable DTO pair:
The getters and setters are easy to auto-generate an any major
IDE, but the build() method requires a bit more tedious work. Well, tedious if there are 20 or 100 rather than the mere 2 in this example. Or one can fiddle about with code generation to take care of it. But I'd prefer something that scales better as the number of fields increases, with less redundant code. We can use the Prototype
pattern, implement Cloneable, and let clone() take care of all the copying:
This still seems like an annoying amount of boilerplate code for something that really
should be simpler, in my opinion. But that's what I've come up with so far, in my attempts to reconcile my preference for immutable objects with my dislike of constructors with long lists of unlabeled arguments. Open to further suggestions...