2016-06-25 3 views
0

Zur Zeit habe ich eine Klasse namens MatrixValue, die ich zu einem unveränderlichen Objekt machen möchte, so dass alle meine Methoden, die mit einer Instanz von MatrixValue interagieren, ihre innere Matrix nicht ändern können. Das Problem besteht jedoch darin, dass eine der Mitgliedsvariablen ein veränderbares Objekt ist, das RealMatrix heißt und alle tatsächlichen Daten der Matrix speichert. Ich habe bereits eine defensive Kopie in den Konstruktor eingefügt und alle Mutator-Methoden losgeworden. Hier ist, was meine Klasse sieht wie bisher:Java Wrapper-Klasse unveränderlich mit mutierbaren Membern erstellen

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

Das Problem jetzt ist, dass, wenn jemand anruft matrixValue.getMatrix().setEntry(row, col, value); sie sind effektiv in der Lage, den Wert der letzten RealMatrix Membervariable zu ändern. Trotzdem möchte ich Informationen über die RealMatrix zurückgeben können. Was ist der beste Ansatz, um dieses Loch in der Unveränderlichkeit der Klasse zu beheben?

EDIT: Beachten Sie auch, dass einige Matrizen speicherintensiv werden können. Wenn möglich, würde ich eine Lösung bevorzugen, die das Duplizieren unnötiger Informationen minimiert.

+0

Mögliches Duplikat von [Make immutable Java object] (http://stackoverflow.com/questions/18194139/make-immutable-java-object) – astrogeek14

+0

Sie sollten einen Klon der Matrix in der Methode getMatrix() erstellen. –

+0

Danke Michael Ich denke, das ist, was ich tun werde. –

Antwort

0

Verwenden Sie eine Schnittstelle auf RealMatrix. Eine mögliche Schnittstelle könnte Matrix genannt werden. Ihre interne Repräsentation könnte dann RealMatrix verwenden und dann, wo Sie Ihre externe API bereitstellen, können Sie anstelle des Rückgabetyps von RealMatrix stattdessen eine Matrix zurückgeben.

class RealMatrix implements { 
// getters and setters 
} 

interface Matrix { 
// only getters 
} 
0

Der einfachste Weg, wahrscheinlich zu tun, ist eine defensive Kopie matrix vom getMatrix() Methode zurückzukehren. Sie können es jedes Mal klonen und in der Methode zurückgeben oder eine Kopie im Konstruktor erstellen und nur dieselbe Kopie in der Methode zurückgeben.

Allerdings würde ich denken, was die Absicht MatrixValue ist. Wenn es eine unveränderliche Darstellung RealMatrix ist, würde ich prüfen, eine Schnittstelle für RealMatrix und MatrixValue zu komponieren wie folgt:

interface Matrix { 
    // getters for Matrix 
} 

RealMatrix und MatrixValue die Schnittstelle implementieren wie folgt:

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 
} 

Diese bieten die Absicht, dass RealMatrix und MatrixValue sind veränderliche und immltable Darstellung von Matrix entsprechend und ermöglichen API-Aufrufer, die Werte von MatrixValue bu zu erhalten t kann es nicht ändern.

Übrigens, erstellen Sie eine neue Instanz von Array2DRowRealMatrix in MatrixValue Konstruktor möglicherweise nicht genug, um eine defensive kopieren, weil das Array von double[][] extern geändert werden kann. Sie müssen eine Kopie des Arrays mit Arrays.copyOf oder System.arraycopy für jede Dimension des Arrays erstellen, um Mutationen zu vermeiden.

Verwandte Themen