An object is considered immutable if its state cannot change after it is constructed.
Immutable objects are particularly useful in concurrent applications.
Since they cannot change state, they cannot be corrupted by thread
interference or observed in an inconsistent state.
Strategy for Defining Immutable Objects
The following rules define a simple strategy for creating immutable objects.
- Don't provide "setter" methods — methods that modify fields or objects referred to by fields.
- Make all fields
final
andprivate
. - Set all instance data in the constructor.
- Don't allow sub-classes to override methods. The simplest way to do this is to declare the class as
final
. A more sophisticated approach is to make the constructorprivate
and construct instances in factory methods. - If the instance fields include references to mutable objects, don't allow those objects to be changed:
- Don't provide methods that modify the mutable objects.
-
Clone mutable objects for which a reference to them is returned.
-
Clone mutable objects for which a reference to them is received.
- Implement a deep clone if the default shallow clone is not correct for a properly behaved immutable object.
Lets add all above rules and make something concrete class implementation.
This is the most simple way of making a class mutable.
Making a class immutable in Java, which includes mutable member variable.
When an immutable class is implemented, mutable objects passed to or returned from an immutable object must be properly cloned. Consider the following class declarations: a DiskDriveInfo class and a User class. The DiskDriveInfo is intended to be immutable. The User encapsulates which user has shared access to the disk drive. The User object with shared access is stored as part of the DiskDriveInfo object. In the following example, the designer of the class was careful to make the class final and all fields private, and to provide only getter methods. Is the DiskDriveInfo class immutable? If not, what needs to be done to make it so?
If we run the program we will get output like this:
The problem is that the DiskDriveInfo constructor receives a reference to the User object and does not make a copy, or clone, of this object. Therefore, the DiskDriveInfo constructor receives a copy of the reference to the User object. Now the DiskDriveInfo object's driveShare field and the local variable, share1, in main of class Test, reference the same object. Therefore, any changes made through either reference affect the same object. Figure shows the object layout after the code at //1 is executed.
After the code at //2 is executed, the object layout looks as shown in Figure
Notice that because the reference to the User object is not cloned, both the share1 and driveShare references share the same User object. After the code at //3 is executed, the object layout as shown in Figure.
To correct this problem, the DiskDriveInfo class must clone any mutable object to which it receives a reference. It then has a reference to its own copy of the object that cannot be changed by other code.
The modified DiskDriveInfo class that supports cloning looks like this:
Achieving Immutability with Builder Design Pattern:
No comments :
Post a Comment