我是否总是需要克隆对象以确保封装在 Java 中?
Do I always need to clone an object to ensure encapsulation in Java?
给定一个 Outer
class,它引用 Inner
class 的一个对象作为参数:
public class Outer {
private Inner inner;
public Outer(Inner inner) {
// fails
// this.inner = inner;
// passes
this.inner = this.clone(inner);
}
public Inner getInner() {
return this.inner;
}
private Inner clone(Inner inner) {
return new Inner(inner.getInnerValue());
}
}
和只有整数值的Inner
class
public class Inner {
private int innerValue;
public Inner(int innerValue) { this.innerValue = innerValue; }
public void setInnerValue(int innerValue) {
this.innerValue = innerValue;
}
public int getInnerValue() {
return this.innerValue;
}
}
测试
class OuterTest {
@Test
void testEncapsulation() {
Inner inner = new Inner(3);
Outer outer = new Outer(inner);
inner.setInnerValue(4);
assertEquals(3, outer.getInner().getInnerValue());
}
}
只有在我克隆 inner
时才会通过(参见评论 fails
)。大体上是这样吗?那么我是否需要在每次通过引用时都克隆每个引用?
不,不总是。
另一种方法是使 Inner
return 的所有设置器成为 Inner
的新实例,而不是设置 this
的字段。通常这些 setter 的名称为“+”,例如 withInnerValue
:
public Inner withInnerValue(int innerValue) {
return new Inner(innerValue);
}
然后在测试中,你将被迫改为这样做:
void testEncapsulation() {
Inner inner = new Inner(3);
Outer outer = new Outer(inner);
inner = inner.withInnerValue(4); <---- this is forced to change
assertEquals(3, outer.getInner().getInnerValue());
}
通过重写 Inner
的设置器,您已将其设为 不可变,也就是说,一旦实例创建,其字段便无法更改。
保持简单,无需克隆等:
class OuterTest {
@Test
void testEncapsulation() {
Inner inner = new Inner(3){{
setInnerValue(4);
}};
Outer outer = new Outer(inner);
assertEquals(3, outer.getInner().getInnerValue());
}
}
给定一个 Outer
class,它引用 Inner
class 的一个对象作为参数:
public class Outer {
private Inner inner;
public Outer(Inner inner) {
// fails
// this.inner = inner;
// passes
this.inner = this.clone(inner);
}
public Inner getInner() {
return this.inner;
}
private Inner clone(Inner inner) {
return new Inner(inner.getInnerValue());
}
}
和只有整数值的Inner
class
public class Inner {
private int innerValue;
public Inner(int innerValue) { this.innerValue = innerValue; }
public void setInnerValue(int innerValue) {
this.innerValue = innerValue;
}
public int getInnerValue() {
return this.innerValue;
}
}
测试
class OuterTest {
@Test
void testEncapsulation() {
Inner inner = new Inner(3);
Outer outer = new Outer(inner);
inner.setInnerValue(4);
assertEquals(3, outer.getInner().getInnerValue());
}
}
只有在我克隆 inner
时才会通过(参见评论 fails
)。大体上是这样吗?那么我是否需要在每次通过引用时都克隆每个引用?
不,不总是。
另一种方法是使 Inner
return 的所有设置器成为 Inner
的新实例,而不是设置 this
的字段。通常这些 setter 的名称为“+”,例如 withInnerValue
:
public Inner withInnerValue(int innerValue) {
return new Inner(innerValue);
}
然后在测试中,你将被迫改为这样做:
void testEncapsulation() {
Inner inner = new Inner(3);
Outer outer = new Outer(inner);
inner = inner.withInnerValue(4); <---- this is forced to change
assertEquals(3, outer.getInner().getInnerValue());
}
通过重写 Inner
的设置器,您已将其设为 不可变,也就是说,一旦实例创建,其字段便无法更改。
保持简单,无需克隆等:
class OuterTest {
@Test
void testEncapsulation() {
Inner inner = new Inner(3){{
setInnerValue(4);
}};
Outer outer = new Outer(inner);
assertEquals(3, outer.getInner().getInnerValue());
}
}