这是一个非常简单的问题,我仍然非常不安:
为什么现在广泛接受类通过访问器方法返回对其私有成员的引用?这不完全打破封装原则吗?如果这样可以,那么为什么不公开会员呢??
public class EncapsulationViolator
{
private object abuseMe;
public object AbuseMe
{
get { return abuseMe; }
}
}
编辑我正在考虑的案例是
EncapsulationViolator ev = new EncapsulationViolator();
object o = ev.AbuseMe;
o.SetValue(newValue);
现在,ev的状态因传染性而发生变化,因为其成员滥用状态已发生变化。
在DDD的上下文中,如果对象是聚合根,则不行。我引用
允许外部对象仅保留对根的引用。短暂的 对内部成员的引用可以在一个内部传递出来使用 仅限单一操作。因为root控制访问,所以不能 因内部变化而瞎了。
[ Domain-Driven Design ,Eric Evans]
... setters schmetters ......
答案 0 :(得分:12)
您将C ++术语“引用”与C#按值(其引用)传递对象的事实混淆。
在这种情况下,获取者AbuseMe
的来电者无法换出私有字段abuseMe
。因此,没有违反封装。
EncapsulationViolator x = new EncapsulationViolator();
object y = x.AbuseMe;
y = 17; // I have not changed x.AbuseMe
Debug.Assert(y != x.AbuseMe); // Passes!
此外,属性getter和setter允许对私有字段进行适当的封装,并且在功能上与将它们作为方法实现相同(实际上它们是由编译器实现的方法)。
当您返回对数组的引用时,返回私有变量可以破解封装的一种情况是:
class X
{
private int[] amazing = new int[10];
public int[] Amazing { get { return this.amazing; } }
}
X a = new X();
int[] x = a.Amazing;
int[] y = a.Amazing;
x[2] = 9;
Debug.Assert(x[2] != y[2]); // Fails!
答案 1 :(得分:10)
这取决于成员是什么类型的对象。如果它是一个字符串,那么它是不可变的,所以你不能改变字符串。
如果它是一个可变对象,您可以从类外部更改对象的内容,但不能替换该对象本身。
如果对象不可能从类外部更改,则getter应该返回该对象的不可变版本。
如果你做错了,模式可能会破坏封装,但是正确完成封装是完整的。
答案 2 :(得分:8)
我不认为它打破了封装。该类仍然决定AbuseMe
的返回值来自何处。它可能来自不同的成员,也可能每次都可以重新创建或复制。
关键是该类决定了它允许用户对该成员执行的操作(获取/设置或两者及其可见性),它可以执行验证并防止设置无效值,并且用户不需要知道价值来自何处。
此外,如果要将自定义逻辑添加到get / set方法,则可以在不破坏与其他程序集的兼容性的情况下执行此操作。
答案 3 :(得分:1)
这只是语法糖。它与Java的getXXX和setXXX方法没有任何不同。
答案 4 :(得分:1)
getter和setter的重点是强制执行封装。重点是您不直接授予对象访问权限,但强制它由您定义的函数访问。吸气剂和制定者是封装。如果您决定只返回该对象,那么这就是您的业务,但是您不允许直接访问而不会遇到吸气剂。
答案 5 :(得分:1)
IMO - 这里的答案太多了促进吸气者/制定者。 getters / setter非常适合程序代码,你可以做一些计算并设置结果或获取值并做出决定。
OO编程中一个众所周知的原则是Tell don't ask,它基本上说你不应该要求其内部状态的对象做出决定。
话虽这么说,我自己也使用访问者/属性。但是,如果可能的话,我会尽量避免它们。