Immutable objects are great because they require no special care or feeding in multi-threaded applications. However many objects fall just short of being naturally immutable. For example, an order which is submitted, processed, and is assigned a permanent ID once the order is filled. The ID cannot be given at the time the order is created and submitted, but arrives later (or perhaps never).
Possible solutions:
Are these solutions reasonable? Any other ideas? Thanks.
Make the class immutable and make null
a valid value for the ID. When you have an ID to assign, replace the existing immutable object with a new one that is identical except that it has the new ID instead of the old one. I like to use methods called withX
for this purose.
Foo foo = new Foo("bar");
...
foo = foo.withId(12345); // replace foo with new derived object
They sound like two different objects to me, an order and a filled order. One being a copy of the other with an id...
What is it about immutability you're interested in? How would it affect your domain model? For example, I've seen "domain" objects have an id field just to please hibernate but they won't have an id value until hibernate gives it to them. In this case, the "domain" object is weak.
The model of the object from the business perspective (in my academic example) would suggest that an id isn't needed. However, the model from a technical perspective requires an id (more specifically, hibernate wants one). There's obvious tension here so I like to be clear what I'm trying to model (business or technical).
Out of interest, what does the id represent in your example?
So, when we think about the idea of identity
(in the Eric Evans sense), for an object or Entity
to exist, it must have a identity (Entities
are equal if their identities are equal regardless of whether their content is equal). For me that means
It doesn't make sense to new up an
Entity
without an identity (in this case anid
)
I'd also suggest
There is no such thing as an "almost" immutable object, it is either immutable or it isn't
If you use a work around like suggested above, you should be upfront about the fact that your object is no longer immutable. This may be ok (again, why do you want immutability?). I don't think having a domain object that can have a null for an id (that is later replaced in a copy) is a good idea. It makes for a "special case" which can be avoided by modelling it differently and opens you up to handling the special case in lots of places (potentially).
I think that the second approach is best, using synchronization as appropriate. The overheads of lazy initialization and synchronizing of an object getter are probably insignificant.
I also suspect that the first approach will have equivalent (or worse) overheads if you compare complete implementations. For instance, it will either need to synchronize the Map, or use a Concurrent map that has overheads of its own. And the fact that the map is a shared data structure means that the chance of contention will be higher than for a getter on a (generally) unshared object.
Define an ID-holder class which contains a field for the ID. When an order is created, create a new ID-holder object with a blank ID and assign it to the order. The order itself will technically be shallow-immutable, but provided no attempt is made to "re-use" ID-holder objects for different orders, the only changes that may occur to the ID-holder object will be those which should be applied to the order or any copies thereof.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With