[英]Returning an immutable reference to a mutable object in Java
基本上,我在Java中有一个可变对象,并且某个类的几种方法都可以访问和修改其状态。 存储在对象中的数据也由另一个类使用,但是不同之处在于,不应仅允许使用第二类来修改数据。
在C ++中,我通常只将const
引用传递给手头的对象,但是我意识到Java中没有直接的等效项。
为了澄清起见,以下代码片段显示了我的想法:
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);
}
}
假设SizeInfo
是一个大对象,所以我不想进行成员复制,而只是通过引用传递它。 上面的代码成功地允许任何Figure
存取SizeInfo
对象的数据,但也允许Figure
修改该对象。 由此类行为引起的错误可能很难跟踪,因此我想向SizeInfo
传递“不可变的引用”。
到目前为止,我发现的最佳解决方案是创建SizeInfo
的非静态内部类, SizeInfo
仅包含getter:
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; }
}
使用此代码,您只需要将Figure
的方法签名从onSizeChanged(SizeInfo)
更改为onSizeChanged(SizeInfo.Export)
,并将sizeInfo.export()
传递给该方法而不是sizeInfo
即可使其按预期工作。 从客户端使用这非常容易,但是由于必须重复每个getter两次而导致的代码冗余绝对不是很好。 仅将吸气剂放置在SizeInfo.Export
并将每个sizeInfo.getBaz()
替换为sizeInfo.export().getBaz()
方法更加糟糕。 这就是为什么我正在寻找一种更优雅的方法。
我意识到,就SizeInfo
而言,它太大而不能创建一个逐级克隆,因此可能无法相信这个特定示例。 但是,还有无数其他示例。 例如,如果我有一个可变的对象表示图像的ARGB数据(可能是由于使用某些数学公式逐个像素生成了图像),然后想要将其传递给一种方法,该方法应该对其进行修改,问题仍然会出现。
创建一个包含吸气剂的ReadOnlySizeInfo
接口,使SizeInfo实现该接口,然后将该接口而不是SizeInfo传递给onSizeChanged()
。
您仍然会传递一个可变的对象,但是Figure对此并不了解:它所接收到的所有信息仅是ReadOnlySizeInfo
。 它仍然可以对对象进行强制转换和变异,但这不再是一个错误:这将是一种邪恶的行为。
您可以创建一个接口,例如SizeInfoView
,其中仅包含吸气剂。 然后, SizeInfo
将实现该接口,但还要添加setter。 Figure
将仅收到对SizeInfoView
接口的引用。 调用者当然仍然可以向下转换为SizeInfo
,但是在C ++中,使用const_cast
会遇到相同的问题。 通常足以防止发生意外。
但是请记住,您得到的是不可修改的对象,而不是不可变的对象。 不同之处在于其他人可以对其进行修改,并且这些更改将反映在不可修改的视图中。 但是同样,对于C ++ const
引用也是如此。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.