Inevitability is best viewed from the perspective of a user API. Therefore, the API of your object must satisfy the following two conditions:
- Do not allow anyone to change the value of an object
- It guarantees that at any time when the user reads or uses the value of the object in the future, he will get the same result
Important Note . In fact, it is normal to have mutable data inside an immutable object if it behaves like an immutable object from the point of view of the API user. For example, consider java.lang.String: although it is usually regarded as the final immutable class, in fact it has a mutable hashCode internal cache field (few know that!).
So, to solve your question, if you want to contain another (mutable) object inside an immutable object, you usually need to do one or more of the following:
- Ensure that no one else can change the value of the mutable object. Usually this means that no one can reference the mutable object, so this is usually only possible if you create the object yourself, and not accept the link from the outside.
- Make a protective deep copy of the mutable object and do not pass links to the new copy. Allow only operations that read a new copy in the public API. If you need to transfer the link to this object, you need to take one more protective copy (so as not to transfer the link to the internal copy).
- Use immutable wrapper for mutable object. Something like Collections.unmodifiableList . This is useful if you want to pass a reference to an internal mutable object, but do not want to expose it to the risk of changes.
All of these solutions are a bit hacky - the best solution overall is to avoid using mutable objects in immutable objects. In the end, he asks for trouble, because sooner or later the volatile link will be changed, and it will be very difficult for you to find the error. You better move to a complete hierarchy of immutable objects (an approach used by languages such as Scala and Clojure)
mikera
source share