How to create an immutable class which has mutable instance object?
Hi everyone;
Sometimes you need an immutable class in your app. Maybe you want to convert your mutable class to immutable class.
Firstly;
Why we need a immutable class or what is advantages of immutable class?
- Thread-safe object
- Cacheable object
How to do an immutable class?
- immutable class must be final
- all properties must be private (access control)
- all properties must be final (can not change)
- using any setter method for properties
For example an immutable class
public final class Employee {
private final String name;
private final Integer age;
public Employee(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- final class
- private final properties
- no setter method
Now we add a mutable class instance to immutable class
For example a mutable class (Address)
public class Address {
private String city;
private String state;
public Address(String city, String state) {
this.city = city;
this.state = state;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Override
public String toString() {
return "Address{" +
"city='" + city + '\'' +
", state='" + state + '\'' +
'}';
}
}
And we add this instance object (Address) to immutable class (Employee)
public final class Employee {
private final String name;
private final Integer age;
private final Address address; //mutable object
public Employee(String name, Integer age, Address address) {
this.name = name;
this.age = age;
Address cloneAddress = new Address(address.getCity(),address.getState()); // deep copy
this.address = cloneAddress;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Address getAddress() {
return new Address(address.getCity(),address.getState());
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}
Did you notice that how define mutable class inside constructor method and getter method of mutable class?
Firstly test this immutable class
public class TestClass{
public static void main(String[] args) {
Address address = new Address("city1","state1");
Employee employee = new Employee("employee1",20,address);
System.out.println(employee);
//after change
address.setCity("city2");
address.setState("state2");
System.out.println(employee);
Address address2 = employee.getAddress();
//after change other way
address2.setCity("city3");
address2.setState("state3");
System.out.println(employee);
}
}
Output is :
Employee{name='employee1', age=20, address=Address{city='city1', state='state1'}}
Employee{name='employee1', age=20, address=Address{city='city1', state='state1'}}
Employee{name='employee1', age=20, address=Address{city='city1', state='state1'}}
You can see mutable class in immutable class can not change values.
But if I change our class structure like below
public final class Employee {
private final String name;
private final Integer age;
private final Address address; //mutable object
public Employee(String name, Integer age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Address getAddress() {
return address;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}
when run code example, output is :
Employee{name='employee1', age=20, address=Address{city='city1', state='state1'}}
Employee{name='employee1', age=20, address=Address{city='city2', state='state2'}}
Employee{name='employee1', age=20, address=Address{city='city3', state='state3'}}
In actually, because of changing of mutable class our immutable class changed.
What I did?
- In consturctor of immutable class, I did deep copy :
Address cloneAddress = new Address(address.getCity(),address.getState()); // deep copy
this.address = cloneAddress;
2. In getter method of mutable class inside immutable class :
return new Address(address.getCity(),address.getState());
I hope, it was useful for you.
Thanx to reading.