2016-04-30 16 views
0

Grundsätzlich habe ich ein veränderbares Objekt in Java und auf seinen Zustand wird sowohl zugegriffen als auch durch verschiedene Methoden einer bestimmten Klasse geändert. Die im Objekt gespeicherten Daten werden auch von einer anderen Klasse verwendet. Der Unterschied besteht jedoch darin, dass die zweite Klasse die Daten nicht ändern darf, nur um sie zu verwenden.Einen unveränderlichen Verweis auf ein veränderbares Objekt in Java zurückgeben

In C++ würde ich normalerweise nur eine const Referenz auf das Objekt übergeben, aber ich weiß, dass es keine direkte Entsprechung in Java gibt.

Nur um zu klären, der folgende Code-Schnipsel zeigt, was ich im Sinn haben:

public interface Figure 
{ 
    void onSizeChanged(SizeInfo info); 
    void draw(); 
} 
public class FigureView extends View 
{ 
    private Figure figure; 
    private SizeInfo sizeInfo; 

    ... 

    public void onResize() 
    { 
     //Modify the state of sizeInfo, then pass it to the figure. 
     figure.onSizeChanged(sizeInfo); 
    } 
} 

Lasst uns sagen, dass SizeInfo ein großes Objekt ist, so will ich nicht eine element Kopie machen, aber nur passieren es als Referenz. Der obige Code ermöglicht es Figure, auf die Daten des SizeInfo Objekts zuzugreifen, aber es ermöglicht auch das Figure, das Objekt zu ändern. Fehler, die durch ein solches Verhalten verursacht werden, können schwer zu verfolgen sein. Daher möchte ich eine "unveränderliche Referenz" an die SizeInfo übergeben.

Die beste Lösung, die ich bisher gefunden habe, ist eine nicht-statische innere Klasse von SizeInfo zu schaffen, die von Getter besteht nur:

public class SizeInfo 
{ 
    //These represent the large set of data inside the class. 
    private long foo; 
    private double bar; 
    private Export mExport = new Export(); 

    //Setters (only available if you have a direct reference to SizeInfo): 
    public void incrementFoo() 
    { 
     foo++; 
    } 
    public void setBar(double bar) 
    { 
     this.bar = bar; 
    } 

    //SizeInfo getters: 
    public long getFoo() 
    { 
     return foo; 
    } 
    public double getBar() 
    { 
     return bar; 
    } 
    public double getBaz() 
    { 
     return bar * foo; 
    } 

    //A non-static inner class: 
    public class Export 
    { 
     public long getFoo() { return foo; } 
     public double getBar() { return bar; } 
     public double getBaz() { return bar * foo; } 
    } 
    public Export export() { return mExport; } 
} 

Mit diesem Code, müssen Sie nur die Methodensignatur in Figure ändern von onSizeChanged(SizeInfo) bis onSizeChanged(SizeInfo.Export) und übergeben sizeInfo.export() an die Methode statt sizeInfo, damit es wie erwartet funktioniert. Dies ist sehr einfach von der Client-Seite zu verwenden, aber die Code-Redundanz, die dadurch verursacht wird, dass jeder Getter zweimal wiederholt werden muss, ist definitiv nicht elegant. Die Alternative, die Getter nur in SizeInfo.Export zu platzieren und jede sizeInfo.getBaz() durch sizeInfo.export().getBaz() zu ersetzen, ist noch schlimmer. Deshalb suche ich einen eleganteren Ansatz.

Ich realisiere, dass dieses bestimmte Beispiel möglicherweise nicht glaubhaft in Bezug auf SizeInfo ist zu groß, um nur ein memberwise Klon zu erstellen. Es gibt jedoch unzählige andere Beispiele. Zum Beispiel, wenn ich ein veränderliches Objekt hätte, das die ARGB-Daten eines Bildes repräsentiert (vielleicht weil das Bild Pixel für Pixel unter Verwendung einiger mathematischer Formeln erzeugt wurde), und es dann an eine Methode übergeben wollte, die nicht in der Lage sein sollte Um es zu ändern, würde das Problem immer noch auftreten.

Antwort

0

Sie könnten eine Schnittstelle erstellen, sagen SizeInfoView, die nur die Getter enthält. Dann würde SizeInfo diese Schnittstelle implementieren, aber auch Setter hinzufügen. Figure würde nur einen Verweis auf die SizeInfoView Schnittstelle erhalten. Der Aufrufer kann natürlich immer noch auf eine SizeInfo downcast, aber Sie hätten das gleiche Problem in C++ mit const_cast. Es ist normalerweise gut genug, um Unfälle zu vermeiden.

Bedenken Sie aber, dass Sie ein unmodifiable Objekt, wenn es darum, nicht ein unveränderlich Objekt.Der Unterschied besteht darin, dass jemand anders sie ändern könnte und die Änderungen in der nicht änderbaren Ansicht widergespiegelt würden. Aber wiederum gilt dasselbe für C++ const Referenzen.

0

Erstellen Sie eine ReadOnlySizeInfo-Schnittstelle, die die Getter enthält, stellen Sie SizeInfo diese Schnittstelle bereit und übergeben Sie die Schnittstelle anstelle von SizeInfo an onSizeChanged().

Sie werden immer noch ein veränderbares Objekt übergeben, aber die Figur weiß nichts darüber: Alles, was sie darüber weiß, ist, dass es ein ReadOnlySizeInfo ist. Es könnte das Objekt immer noch werfen und mutieren, aber das wäre kein Fehler mehr: Es wäre ein böses Verhalten.

Verwandte Themen