对象的“公开代表”可能由以下哪个引起:
我知道答案是4,但我不确定为什么,我对揭露代表的理解并不完全清楚。
编辑:明确答案
答案 0 :(得分:2)
我从未听过那个词,所以我用谷歌搜索了它。本文非常清楚地解释了这一点:
http://www.cs.newpaltz.edu/~pletcha/oop_chap5_1.html
公开rep意味着违反对象方法控制其状态的规则。例如,如果一个对象有实例变量和mutators来改变它们的值,那么该对象就有一种控制其状态的方法。如果我致电foo.setBar(5)
,那么foo.getBar()
如果文档说getBar
返回setBar
设置的值,则最好返回5。
我将解释为什么你给出的三个描述中的每一个都暴露了一个对象的表示(或更普遍地说,打破封装):
不将其类中的变量声明为私有。
这是最简单的。如果实例变量是公共的,则JVM中的任何内容都可以在同一对象/类中的代码外部更改其值。如果我们调用foo.setBar(5)
然后调用foo.getBar()
,我们可能会得到5以外的内容,因为bar
是公共范围,因此另一个代码区域可能会对其进行变更。
允许对象中的变量引用传递给它的对象作为其构造函数的参数。
这个让我花了一分钟才能理解,但是如果你把一个对象及其依赖关系看作一个单元就有意义了。
如果Foo
有Bar
且Bar
int
有x
,则Foo
可以查看并控制{{1} x
上的属性,因为它有一个引用。如果我创建bar
的实例并在Foo
的构造函数中传递对Bar
的实例的引用,则会给出Foo
具有完全控制权的外观。但事实并非如此。例如:
Foo
此代码公开了代理,因为public class Foo {
private Bar bar;
public Foo(Bar bar) {
this.bar = bar;
}
// immutable property - can only be read once this object is instantiated
public Bar getBar() {
return this.bar;
}
}
public class Bar {
private int x;
public Bar(int x) {
this.x = x;
}
public int getX() {
return this.x;
}
public void setX(int x) {
this.x = x;
}
}
// some other java class
Bar bar = new Bar(10);
Foo foo = new Foo(bar);
bar.setX(5);
已经做出了一个关键的假设,即它控制foo
。请注意,它对bar
的引用是不可变的。但它并非真正不可改变。只有引用本身是不可变的。创建bar
的代码仍然引用foo
,并且可以在bar
不知道的情况下对其进行变更。
更简单地说,foo
依赖foo
并将其视为自身的一部分。但是bar
实际上可以独立地改变,因此bar
的状态在没有它知道的情况下间接地发生了变化。
允许存储在对象变量中的引用作为在该对象上调用的方法的返回值。
这最容易通过集合来解释。
foo
这违反了合同。要添加栏,您应该拨打public class Foo {
private Collection<Bar> bars = new ArrayList<Bar>();
// immutable property - can only be read once this object is instantiated
public Collection<Bar> getBars() {
return this.bars;
}
public void addBar(Bar bar) {
this.bars.add(bar);
}
public int getBarCount() {
return this.bars.size();
}
}
Foo foo = new Foo();
foo.getBars().add(new Bar(someUnexpectedBar));
System.out.println(foo.getBarCount()); // -> 1
。这就是暴露该方法的原因。通过在addBar
中返回对集合的引用,可以操作底层集合。
起初这似乎微不足道。但是如果getBars
制定了这个规则并且上面的用法违反了规则,那么如果我想重构Foo
就会发生什么(让我们说性能):
Foo
从功能上讲,它是完全相同的。如果你恰当地使用它中的方法,那就没有区别了。但是我们欺骗了。我们抓住了底层集合并对其进行了改变。现在public class Foo {
private Collection<Bar> bars = new LinkedList<Bar>();
private int barCount; // for faster inserts, use a linked list and to maintain fast counts, track the count ourselves by tracking the adds.
// immutable property - can only be read once this object is instantiated
public Collection<Bar> getBars() {
return this.bars;
}
public void addBar(Bar bar) {
this.bars.add(bar);
this.barCount++;
}
public int getBarCount() {
return this.barCount;
}
}
Foo foo = new Foo();
foo.getBars().add(new Bar(someUnexpectedBar));
System.out.println(foo.getBarCount()); // -> 0
方法返回错误的答案(0)。
解决这个问题的方法是返回一个带有原始克隆的新集合。
getBarCount()
甚至
public Collection<Bar> getBars() {
return new ArrayList<Bar>(this.bars);
}