0

I have following classes :

Emp.java

final public class Emp {

    private Integer id;
    private String name;
    private Department department;

    public Emp(Integer id, String name, Department department) {
        this.id = id;
        this.name = name;
        this.department = department;
    }

    public Department getDepartment() {
        return department;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

Department.java

public class Department {

    private Integer id;
    private String name;

    public Department(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }
}

EmployeeTest.java

public class EmployeeTest {

    public static void main(String args[]) {
        Department dept1 = new Department(1, "dept1");
        Emp emp = new Emp(1, "emp1", dept1);
        emp.getDepartment().setName("dept2");
        System.out.println("emp = "+emp);

    }
}

Here Emp class is not purely an immutable class because somehow I am able to change the values of Department (as shown in the example).

What are the best possible changes which will make Emp class a pure Immutable class ?

Nirmal
  • 4,789
  • 13
  • 72
  • 114

5 Answers5

3

In getters for non-primitive field, use this structure

public class Line {

   private final Point start;
   private final Point end;

   public Line(final Point start, final Point end) {
       this.start = new Point(start);
       this.end = new Point(end);
   }

   public Point getStart() {
       return new Point(start);
   }

   public Point getEnd() {
       return new Point(end);
   }
}  

So, simply create new instance of department that is equals to previous

P.S. In my example you can see pure immutable class
EDIT:
Also you can add to Department class copy-contructor

public Department(final Department dep)  
{ ... } 

And to Employer

getDepartment()  
{  
   return new Department(department);  
}
Ilya
  • 29,135
  • 19
  • 110
  • 158
1

If you don't like removing setters and do initialization in a constructor, you can think about returning immutable (from the point of view of the Emp class) objects, which will web objects' copies, in getters (see https://stackoverflow.com/a/128712/1579085).

final public class Emp {

    private Integer id;
    private String name;
    private Department department;

    public Emp(Integer id, String name, Department department) {
        this.id = id;
        this.name = name;
        this.department = (Department) department.clone();
    }

    public Department getDepartment() {
        return (Department) department.clone();
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

And implement the method clone() in Department (which will implement the interface Cloneable) of course.

This approach is suitable, if you need to be able to modify Department, but the objects of the Emp class should be safe from those outer modifications.

Community
  • 1
  • 1
Vic
  • 1,778
  • 3
  • 19
  • 37
  • The `Department` could still be changed in your code. You must do a copy/clone in you constructor as well. – maba Aug 20 '12 at 09:35
  • @maba Yes, but now the `Emp` class is safe, and nobody can break its logic by altering `department`. (I'll correct my answer.) – Vic Aug 20 '12 at 09:56
  • But if I have a reference `dep`to `Department` and use that in the constructor then I can update the `Department` outside the `Emp` by doing `dep.setName("other")` and altered the `department`. – maba Aug 20 '12 at 10:13
  • @maba In that case one can should use a copy again - in the constructor. Sorry, forgot to put in in the code. – Vic Aug 20 '12 at 10:20
1

See Efffective Java:

Item 15: Minimize mutability – 5 rules to follow.

  1. Don’t provide any methods that modify the object’s state
  2. Ensure that the class can’t be extended
  3. Make all fields final
  4. Make all fields private
  5. Ensure exclusive acess to any mutable components
卢声远 Shengyuan Lu
  • 31,208
  • 22
  • 85
  • 130
0

make all attributes final, and remove all setters

gefei
  • 18,922
  • 9
  • 50
  • 67
  • That would make all his classes immutable and that was not his intention. `Department` should be mutable. – maba Aug 20 '12 at 09:25
0

Implement clone() in Department and make Emp return a clone of department in getDepartment().

If references to Department used in constructing Emp are available after construction, then Emp's constructor should clone given Department.

heikkim
  • 2,955
  • 2
  • 24
  • 34