Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: how to deal with "almost" immutable data structures?

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:

  1. Assign an additional unique ID at the time of order creation. Then, when the permanent (order filled) ID comes, store it in a Map. So the order class would be immutable. Then, if the Map key did not exist, we'd know the order was not filled yet. (Should the Map be a static class field?)
  2. Another solution is to make the permanent ID field mutable an apply the appropriate synchronization. Additionally we could limit the ID to be set only once in the object's lifetime.

Are these solutions reasonable? Any other ideas? Thanks.

like image 686
Pete Avatar asked Feb 20 '11 04:02

Pete


4 Answers

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
like image 129
ColinD Avatar answered Oct 22 '22 20:10

ColinD


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 an id)

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).

like image 31
Toby Avatar answered Oct 22 '22 19:10

Toby


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.

like image 2
Stephen C Avatar answered Oct 22 '22 19:10

Stephen C


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.

like image 1
supercat Avatar answered Oct 22 '22 20:10

supercat