繁体   English   中英

在Java中返回对可变对象的不变引用

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM