java - Effective Java 的防御副本

标签 java design-patterns

我正在阅读 Joshua Bloch 的“Effective Java”,第 39 项 make defensive copy,我有一些问题。我总是使用以下结构:

MyObject.getSomeRef().setSomething(somevalue);

这是以下内容的缩写:

SomeRef s = MyClass.getSomeRef();
s.setSomething();
MyObject.setSomeRef(s);

它总是有效,但我想如果我的 getSomeRef() 返回一个副本,那么我的快捷方式将不起作用,我怎么知道 MyObject 的实现是否是使用快捷方式是否安全,是否隐藏?

最佳答案

您违反了 OO 编程的两条规则:

  • 不要和陌生人说话
  • 封装

请注意,这些规则只是规则,它们有时可以,甚至必须被打破。

但是如果某些数据由一个对象拥有,并且该对象应该保证它所拥有的对象的某些不变量,那么它不应该将其可变的内部数据结构暴露给外部。因此需要防御性副本。

另一个常用的习惯用法是返回可变数据结构的不可修改的 View :

public List<Foo> getFoos() {
    return Collections.unmodifiableList(this.foos);
}

这个习惯用法,或防御复制习惯用法,可能很重要,例如,如果您必须确保对列表的每个修改都通过对象:

public void addFoo(Foo foo) {
    this.foos.add(foo);
    someListener.fooAsBeenAdded(foo);
}

如果您不制作防御性副本或返回列表的不可修改 View ,调用者可以直接将 foo 添加到列表中,并且不会调用监听器。

关于java - Effective Java 的防御副本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9743513/

相关文章:

java - ActiveMQ 5.15.9 安全

design-patterns - 静态工厂方法或创建方法

java - 责任链——通过所有链传递请求

design-patterns - CQRS 和命令去抖动

java - 将 Unicode 转换为 UTF-8 byte[] 并保存为字符串 (Java)

java - GWT SimplePager - 为每个下一个和上一个添加历史记录

java - 在 IntelliJ 或 Eclipse 中设置 java 系统属性

java - 使用迭代器返回列表中最大对象位置的通用方法

design-patterns - 会计软件设计模式

c - 如何避免在 C 中使用 global 来检测变量的设置?