制作纯粹的不可变类

时间:2012-08-20 09:06:48

标签: java

我有以下课程:

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);

    }
}

这里 Emp 类不是纯粹的不可变类,因为我能够以某种方式更改 Department 的值(如示例所示)。

哪些最佳可能的更改会使 Emp 类成为纯粹的不可变类?

5 个答案:

答案 0 :(得分:3)

对于非原始字段,在 getters 中,使用此结构

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);
   }
}  

因此,只需创建与之前的

相等的新部门实例

P.S。在我的例子中,你可以看到纯不可变的类
修改
您还可以添加到Department类copy-contructor

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

和雇主

getDepartment()  
{  
   return new Department(department);  
}

答案 1 :(得分:1)

如果你不喜欢删除setter并在构造函数中进行初始化,你可以考虑在getter中返回不可变(从Emp类的角度来看)对象,这将是web对象的副本(见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;
    }
}

当然,在clone()中实现方法Department(将实现接口Cloneable)。

如果您需要能够修改Department,这种方法是合适的,但Emp类的对象应该不受那些外部修改的影响。

答案 2 :(得分:0)

制作所有属性final,并删除所有设置者

答案 3 :(得分:0)

在Department中实施 clone(),并使 Emp getDepartment()中返回部门的克隆。

如果构造Emp中使用的部门的引用在构造之后可用,那么Emp的构造函数应该克隆给定的部门。

答案 4 :(得分:0)

参见Efffective Java:

第15项:尽量减少可变性 - 遵循5条规则。

  1. 不提供任何修改对象状态的方法
  2. 确保无法扩展课程
  3. 将所有字段设为最终
  4. 将所有字段设为私有
  5. 确保对任何可变组件的独占访问