A Strategy for Defining Immutable Objects:
The following rules define a simple strategy for creating immutable objects. Not all java classes documented as "immutable" follow these rules. This does not necessarily mean the creators of these classes were sloppy — they may have good reason for believing that instances of their classes never change after construction. However, such strategies require sophisticated analysis and are not for beginners.- Don't provide "setter" methods — methods that modify fields or objects referred to by fields.
- Make all fields final and private.
- Don't allow subclasses to override methods. The simplest way to do this is to declare the class as final. Even a more sophisticated approach is to make the constructor private 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.
- Don't share references to the mutable objects. Never store references to external, mutable objects passed to the constructor; if necessary, create copies, and store references to the copies. Similarly, create copies of your internal mutable objects when necessary to avoid returning the originals in your methods.
For example: If we have a Student class which holds a reference of Address class as following
class Student{
private String firstName;
private String lastName;
private int studentId;
private Address address;
private Address address;
public Student(String firstName, String lastName, int id){
this.firstName = firstName;
this.lastName = lastName;
this.studentId = id;
}
public String getFirstName(){
return firstName;
}
public void setFirstName(String fName){
firstName = fName;
}
public String getLastName(){
return lastName;
}
public void setLastName(String lName){
lastName = lName;
}
public int getId(){
return studentId;
}
public void setId(int id){
studentId = id;
}
public Address getAddress(){
return address;
}
public void setAddress(Address address){
this.address = address;
}
public Address getAddress(){
return address;
}
this.address = address;
}
}
A simple address class can be written in following way.
class Address {
private int Id;
private String address;
public Address(int studId, String address){
this.id = studId;
this.address = address;
}
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getAddress(){
return address;
}
public void setAddress(String address){
this.address = address;
}
}
Now we can make the Student class immutable by doing following changes:
public static ImmutableStudent createStudent(String fName, String lName, int id, String address){
return new ImmutableStudent(fName, lName, id, address);
}
private int Id;
private String address;
public Address(int studId, String address){
this.id = studId;
this.address = address;
}
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getAddress(){
return address;
}
this.address = address;
}
}
Now we can make the Student class immutable by doing following changes:
final class ImmutableStudent{
private final String firstName;
private final String lastName;
private final int studentId;
private String address;
private String address;
private ImmutableStudent(String firstName, String lastName, int id, String address){
this.firstName = firstName;
this.lastName = lastName;
this.studentId = id;
this.address = address;
this.address = address;
}
public static ImmutableStudent createStudent(String fName, String lName, int id, String address){
return new ImmutableStudent(fName, lName, id, address);
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public int getId(){
return studentId;
}
public Address getAddress(){
return new Address(studentId, address);
}
public Address getAddress(){
return new Address(studentId, address);
}
}
instead of passing String address in createStudent factory method we can pass a copy of address
as following;
1. Change private String address; to private String Address;// class
2. Change the method as following
public static ImmutableStudent createStudent(String firstName, String lastName, int id, Address address){
// Address address =(Address) address.clone(); // if clone not supported then
Address address = new Address(studentId, address.getAddress());
return new ImmutableStudent(firstName, lastName, id, address);
}
// Address address =(Address) address.clone(); // if clone not supported then
Address address = new Address(studentId, address.getAddress());
return new ImmutableStudent(firstName, lastName, id, address);
}
3. Change the getAddress() as following
public Address getAddress(){
return new Address(studentId, address.getAddress());
// or can be a clone if cone supported, return (Address)address.clone();
}
return new Address(studentId, address.getAddress());
// or can be a clone if cone supported, return (Address)address.clone();
}
It will be a good idea to change the address class as immutable Address class to avoid cloning or creating new copy of Address Object in ImmutableStudent class.
final class Address {
private final int Id;
private final String address;
public Address(int studId, String address){
this.id = studId;
this.address = address;
}
public int getId(){
return id;
}
public String getAddress(){
return address;
}
Now we can remove the factory method from ImmutableStudent class and can pass address reference in constructor by making constructor public as shown here
final class ImmutableStudent {
private final String firstName;
private final String lastName;
private final int studentId;
private final Address address;
private final Address address;
public ImmutableStudent(String firstName, String lastName, int id, Address address){
this.firstName = firstName;
this.lastName = lastName;
this.studentId = id;
this.address = address;
this.address = address;
}
public Address getAddress(){
return address;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public int getId(){
return studentId;
}
}
No comments :
Post a Comment