【问题标题】:Java Create Wrapper Class Immutable with Mutable membersJava 创建具有可变成员的不可变包装类
【发布时间】:2016-06-25 18:28:18
【问题描述】:

目前我有一个名为MatrixValue 的类,我想将其制成一个不可变对象,以便与MatrixValue 的实例交互的所有方法都无法更改其内部矩阵。然而,问题在于成员变量之一是一个名为RealMatrix 的可变对象,它存储了矩阵的所有实际数据。我已经在构造函数中加入了防御性复制,并摆脱了任何 mutator 方法。到目前为止,这是我的班级的样子:

public final class MatrixValue extends ExpressionValue{

    /**
     * 
     */
    private static final long serialVersionUID = -4231050452116360135L;
    private final RealMatrix matrix;

    public MatrixValue(RealMatrix matrix){
        this.matrix = new Array2DRowRealMatrix(matrix.getData());
    }

    public MatrixValue(double[][] values){
        matrix = new Array2DRowRealMatrix(values);
    }

    public RealMatrix getMatrix() {
        return matrix;
    }

    @Override
    public String toString(){
        return matrix.getRowDimension() + "," + matrix.getColumnDimension();
    }
}

现在的问题是,如果有人调用matrixValue.getMatrix().setEntry(row, col, value);,他们可以有效地更改最终RealMatrix 成员变量的值。但是,我仍然希望能够返回有关RealMatrix 的信息。修复类不变性中的这个漏洞的最佳方法是什么?

编辑:还请记住,某些矩阵可能会占用大量内存,因此如果可能的话,我希望尽可能减少重复不必要信息的解决方案。

【问题讨论】:

  • 您应该在 getMatrix() 方法中复制矩阵。
  • 谢谢迈克尔,我想这就是我要做的。

标签: java immutability


【解决方案1】:

最简单的方法可能是从getMatrix() 方法返回matrix 的防御性副本。您可以每次都克隆它并在方法中返回,或者在构造函数中复制并仅在方法中返回相同的副本。

但是,我想MatrixValue 的意图是什么。如果它是RealMatrix 的不可变表示,我会考虑为RealMatrixMatrixValue 编写一个接口,如下所示:

interface Matrix {
  // getters for Matrix
}

RealMatrixMatrixValue 将实现接口如下:

public class RealMatrix implements Matrix {
    // getters for Matrix
    // setters for RealMatrix
}

public class MatrixValue extends ExpressionValue implements Martix {
    public MatrixValue(RealMatrix matrix){
        this.matrix = new Array2DRowRealMatrix(matrix.getData());
    }

    // getters for Matrix
}

这意味着RealMatrixMatrixValueMatrix 的可变和不可变表示,并允许API 调用者从MatrixValue 获取值但不能修改它。

顺便说一句,在MatrixValue 构造函数中创建Array2DRowRealMatrix 的新实例可能不足以进行防御性复制,因为double[][] 的数组可以在外部修改。您需要使用Arrays.copyOfSystem.arraycopy 为数组的每个维度制作数组的副本以避免突变。

【讨论】:

  • 您好 Wilson,我也有类似的问题,我喜欢您的界面方法。但是,我使用的 getter 方法相当复杂,所以在我看来这种方法会违反 DRY 原则。你还会推荐在这种情况下使用它吗?
【解决方案2】:

考虑在 RealMatrix 上使用接口。一个可能的接口可能被称为 Matrix。然后,您的内部表示可以使用 RealMatrix,然后在您提供外部 API 的地方,您可以代替使用 RealMatrix 的返回类型返回一个 Matrix。

class RealMatrix implements {
// getters and setters
}

interface Matrix  {
// only getters
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-05
    • 2012-09-27
    • 2014-07-27
    • 2011-04-19
    • 2011-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多