簡體   English   中英

如何有效地實現可變對象的不可變和只讀版本?

[英]How to implement immutable and read-only versions of mutable objects effectively?

語境:

  • package 數據,公開:
public interface _Data {
   public String getData();
}
public class _PackageAPI {
    DataHolder holder;

    public void createHolder(String data) {
        holder = new DataHolder();
        holder.setData(data);
    }

    public void mutateHolder(String data) {
        holder.setData(data);
    }

    public _Data getSnapshot() {
        return DataSnapshot.from(holder.getData());
    }

    public _Data getReader() {
        return holder.readOnly();
    }
}
  • package 數據,包私有:
class DataHolder {
    private String data;

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public _Data readOnly() {
        return new _Data() {
            @Override
            public String getData() {
                return DataHolder.this.data;
            }
        };
    }
}
class DataSnapshot {
    public static _Data from(String data){
        return new _Data() {
            @Override
            public String getData() {
                return data;
            }
        };
    }
}
  • 示例客戶端用法:
package clientPackage;

import data._Data;
import data._PackageAPI;

public class ExampleRunner {

    public static void main(String[] args) {

        _PackageAPI handler;

        System.out.println("Creating...");

        handler = new _PackageAPI();
        handler.createHolder("INITIAL DATA");

        System.out.println("Done creating...");

        _Data initialSnapShot =  handler.getSnapshot();
        _Data initialReader = handler.getReader();

        System.out.println("initialSnapShot holds :" + initialSnapShot.getData() );
        System.out.println("initialSnapShot class :" + initialSnapShot.getClass() );
        System.out.println("initialReader class :" + initialReader.getClass() );

        System.out.println("initialReader holds :" + initialReader.getData() );


        System.out.println("Mutating...");

        handler.mutateHolder("MUTATED DATA");
        _Data subsequentSnapShot =  handler.getSnapshot();
        _Data subsequentReader = handler.getReader();

        System.out.println("Done mutating...");


        System.out.println("initialSnapShot holds :" + initialSnapShot.getData() );
        System.out.println("initialReader holds :" + initialReader.getData() );

        System.out.println("subsequentSnapShot holds :" + subsequentSnapShot.getData() );
        System.out.println("subsequentReader holds :" + subsequentReader.getData() );



    }
}
  • 和控制台 output:
Creating...
Done creating...
initialSnapShot holds :INITIAL DATA
initialSnapShot class :class data.DataSnapshot$1
initialReader class :class data.DataHolder$1
initialReader holds :INITIAL DATA
Mutating...
Done mutating...
initialSnapShot holds :INITIAL DATA
initialReader holds :MUTATED DATA
subsequentSnapShot holds :MUTATED DATA
subsequentReader holds :MUTATED DATA
  • 一個問題:給定getSnapshot()返回一個_Data(class:DataSnapshot $ 1),其方法getData()返回“真實”數據引用,即DataHolder object的變量數據的內容,這是安全的還是可能的變異 DataHolder 利用對此參考的訪問? 如果是,如何?

  • 縮短的第一個問題:是否可以僅使用參考來改變參考引用的 memory 的內容?

(當然解決方案是克隆被引用的字符串。)

  • 第二個問題無論如何都要改變 DataSnapshot$1(_Data 的“不可變”版本)實例?

  • 第三個問題:給定 DataHolder$1(_Data 的“只讀”版本)在內部持有對提供它的 DataHolder 實例的引用,公開這樣的 DataHolder$1 是否安全,或者無論如何都會弄亂 DataHolder$1 中的 DataHolder 實例object?

編輯:如果有的話,我會放一個偏執狂的標簽

這是安全的還是以某種方式可以利用對該參考的訪問來改變DataHolder 如果是,如何?

由於getData返回一個不可變的String ,因此調用者無法通過返回的引用更改任何內容。 您也不能通過String訪問DataHolder 為什么String會知道您的DataHolder class?

反正有變異DataSnapshot$1嗎?

不,因為它是一個匿名的內部 class 只有一個返回參數的方法。 參數是按值傳遞的,因此您無需擔心調用者會在另一端更改其值。 它也是一個String ,這意味着調用者也不會改變 object 。

您可能會問這個問題,因為您看到了initialReader的變化。 好吧,由於DataHolder$1是可變DataHolder的內部 class ,因此即使它沒有任何修改器方法,它也不是真正不可變的。

公開這樣的DataHolder$1是否安全,或者無論如何都會弄亂DataHolder$1 object 中的DataHolder實例?

無法從內部 class 訪問外部 class ,因此由於DataHolder$1中沒有突變器方法,因此您無法從外部對DataHolder進行突變,只有DataHolder$1

但是,如果DataHolder發生變化,這些變化將反映在DataHolder$1上(如您的示例代碼所示),我認為這違背了不變性的目的。


這是我在這種情況下實現不變性的方法。

我會讓DataHolder實現_Data DataHolder當然可以做到這一點,不是嗎? 畢竟它有一個String getData()方法! DataHolder將有一個asReadOnly方法,該方法創建this副本並返回_Data 事實上,我_Data重命名為ReadOnlyData

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM