开发者

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.


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


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.


Make a class immutable by following these guidelines :

a) ensure the class cannot be overridden - make the class final, or use static factories and keep constructors private

b) make fields private and final

c) force callers to construct an object completely in a single step, instead of using a no-argument constructor combined with subsequent calls to setXXX methods (that is, avoid the Java Beans convention)

d) do not provide any methods which can change the state of the object in any way - not just setXXX methods, but any method which can change state

e) if the class has any mutable object fields, then they must be defensively copied when passed between the class and its caller

Link for reference: http://www.javapractices.com/topic/TopicAction.do?Id=29

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜