[英]How to implement immutable and read-only versions of mutable objects effectively?
Context:语境:
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();
}
}
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() );
}
}
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
FIRST QUESTION : given getSnapshot() returns a _Data (of class: DataSnapshot$1) whose method getData() returns the "real" data reference, ie the content of the variable data of the DataHolder object, is this safe or is it somehow possible to mutate DataHolder leveraging access to this reference?第一个问题:给定getSnapshot()返回一个_Data(class:DataSnapshot $ 1),其方法getData()返回“真实”数据引用,即DataHolder object的变量数据的内容,这是安全的还是可能的变异 DataHolder 利用对此参考的访问? If yes, how?
如果是,如何?
FIRST QUESTION SHORTENED : is it anyhow possible to mutate content of the memory referenced by a reference, using only the reference?缩短的第一个问题:是否可以仅使用参考来改变参考引用的 memory 的内容?
(Of course solution to this is to clone the String being referenced.) (当然解决方案是克隆被引用的字符串。)
SECOND QUESTION : is there anyway to mutate a DataSnapshot$1 (the "immutable" version of _Data) instance?第二个问题:无论如何都要改变 DataSnapshot$1(_Data 的“不可变”版本)实例?
THIRD QUESTION : given DataHolder$1 (the "readOnly" version of _Data) holds internally a reference to the DataHolder instance providing it, is it safe to expose such a DataHolder$1, or is there anyway to mess with the DataHolder instance from the DataHolder$1 object?第三个问题:给定 DataHolder$1(_Data 的“只读”版本)在内部持有对提供它的 DataHolder 实例的引用,公开这样的 DataHolder$1 是否安全,或者无论如何都会弄乱 DataHolder$1 中的 DataHolder 实例object?
EDIT: I would have put a paranoïd tag if there was one编辑:如果有的话,我会放一个偏执狂的标签
is this safe or is it somehow possible to mutate
DataHolder
leveraging access to this reference?这是安全的还是以某种方式可以利用对该参考的访问来改变
DataHolder
? If yes, how?如果是,如何?
Since getData
returns a String
, which is immutable, the caller can't change anything through the returned reference.由于
getData
返回一个不可变的String
,因此调用者无法通过返回的引用更改任何内容。 You can't access a DataHolder
through a String
either.您也不能通过
String
访问DataHolder
。 Why would String
know about your DataHolder
class?为什么
String
会知道您的DataHolder
class?
is there anyway to mutate a
DataSnapshot$1
?反正有变异
DataSnapshot$1
吗?
No, because it is an anonymous inner class that only has one method that returns a parameter.不,因为它是一个匿名的内部 class 只有一个返回参数的方法。 Parameters are passed by value , so you don't need to worry about callers changing their values on the other side.
参数是按值传递的,因此您无需担心调用者会在另一端更改其值。 It's also a
String
, which means the callers won't be mutating the object either.它也是一个
String
,这意味着调用者也不会改变 object 。
You might be asking this because you saw how initialReader
has changed.您可能会问这个问题,因为您看到了
initialReader
的变化。 Well, since DataHolder$1
is an inner class of the mutable DataHolder
, it's not really immutable even if it doesn't have any mutator methods.好吧,由于
DataHolder$1
是可变DataHolder
的内部 class ,因此即使它没有任何修改器方法,它也不是真正不可变的。
is it safe to expose such a
DataHolder$1
, or is there anyway to mess with theDataHolder
instance from theDataHolder$1
object?公开这样的
DataHolder$1
是否安全,或者无论如何都会弄乱DataHolder$1
object 中的DataHolder
实例?
There is no way to access the outer class from the inner class , so since there are no mutator methods in DataHolder$1
, you can't mutate DataHolder
from the outside, with only a DataHolder$1
. 无法从内部 class 访问外部 class ,因此由于
DataHolder$1
中没有突变器方法,因此您无法从外部对DataHolder
进行突变,只有DataHolder$1
。
However, if DataHolder
changes, the changes will reflect on DataHolder$1
(as shown in your sample code), which I think defeats the purpose of immutability.但是,如果
DataHolder
发生变化,这些变化将反映在DataHolder$1
上(如您的示例代码所示),我认为这违背了不变性的目的。
Here's how I would implement immutability in this scenario.这是我在这种情况下实现不变性的方法。
I would make DataHolder
implement _Data
.我会让
DataHolder
实现_Data
。 DataHolder
certainly can do this, can't it? DataHolder
当然可以做到这一点,不是吗? It has a String getData()
method after all!毕竟它有一个
String getData()
方法! DataHolder
would have an asReadOnly
method that creates a copy of this
and returns _Data
. DataHolder
将有一个asReadOnly
方法,该方法创建this
副本并返回_Data
。 In fact, I'd rename _Data
to ReadOnlyData
.事实上,我
_Data
重命名为ReadOnlyData
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.