【发布时间】:2011-03-30 20:51:14
【问题描述】:
在什么情况下应该使用公共字段,而不是属性或 getter 和 setter 方法(不支持属性)?究竟在哪里推荐使用它们,为什么,或者,如果不是,为什么仍然允许它们作为语言功能?毕竟,它们打破了允许和鼓励 getter 和 setter 的面向对象的封装原则。
【问题讨论】:
标签: oop encapsulation public-fields
在什么情况下应该使用公共字段,而不是属性或 getter 和 setter 方法(不支持属性)?究竟在哪里推荐使用它们,为什么,或者,如果不是,为什么仍然允许它们作为语言功能?毕竟,它们打破了允许和鼓励 getter 和 setter 的面向对象的封装原则。
【问题讨论】:
标签: oop encapsulation public-fields
主要原因与 OOP 封装无关(尽管人们经常这么说),而与版本控制有关。
确实,从 OOP 的角度来看,人们可能会争辩说字段比“盲目”属性更好,因为缺乏封装比假装封装然后将其吹走的东西更清楚。如果封装很重要,那么最好看看它什么时候不存在。
从外部看,名为 Foo 的属性与名为 Foo 的公共字段不同。在某些语言中这是显式的(该语言不直接支持属性,因此您有 getFoo 和 setFoo),而在某些语言中是隐式的(C# 和 VB.NET 直接支持属性,但它们不是二进制兼容的如果将字段更改为属性,则使用字段和编译为使用字段的代码将中断,反之亦然。
如果您的 Foo 只是对底层字段进行“盲目”设置和写入,那么 目前 与公开该字段相比没有封装优势。
但是,如果以后需要利用封装来防止无效值(您应该始终防止无效值,但也许您在第一次编写类时没有意识到某些地方无效,或者可能是“有效”已随范围更改而更改),包装记忆评估,触发对象中的其他更改,触发更改事件,防止昂贵的不必要的等效集等等,那么您无法在不中断的情况下进行更改运行代码。
如果类在相关组件的内部,这不是问题,如果字段在一般 YAGNI 原则下合理读取,我会说使用字段。然而,YAGNI 在组件边界上的表现并不那么好(如果我今天确实需要我的组件工作,我当然我可能需要它在你更改组件后工作明天我的依赖),所以先发制人地使用属性是有意义的。
【讨论】:
使用 get 而不是公共字段的原因只有一个(*):惰性求值。 IE。您想要的值可能存储在数据库中,或者可能需要很长时间才能计算,并且不希望您的程序在启动时对其进行初始化,但仅在需要时进行。
使用 set 而不是 public 字段只有一个原因(*):其他字段修改。 IE。当目标字段的值发生变化时,您会更改其他字段的值。
在每个字段上强制使用 get 和 set 与YAGNI 原则相矛盾。
如果你想从一个对象中暴露一个字段的值,那就暴露它! 创建一个具有四个独立字段的对象并强制它们都使用 get/set 是完全没有意义的或属性访问。
*:其他原因,例如可能的数据类型更改是没有意义的。事实上,无论你使用a = o.get_value()而不是a = o.value,如果你改变get_value()返回的类型,你每次使用都必须改变,就像你改变value的类型一样。
【讨论】:
让我们先看看问题为什么我们需要访问器(getter/setter)?您需要它们能够在分配新值/读取值时覆盖行为。您可能想要添加缓存或返回计算值而不是属性。
您的问题现在可以形成为我总是想要这种行为吗?我可以想到这根本没有用的情况:结构(C 中的structs 是什么)。传递 parameter object 或包含要插入到 Collection 中的多个值的类是实际上不需要访问器的情况:对象只是变量的容器。
【讨论】:
这很难说,但在我看来,公共字段只有在使用结构时才有效。
struct Simple
{
public int Position;
public bool Exists;
public double LastValue;
};
但不同的人有不同的想法:
http://kristofverbiest.blogspot.com/2007/02/public-fields-and-properties-are-not.html
http://blogs.msdn.com/b/ericgu/archive/2007/02/01/properties-vs-public-fields-redux.aspx
http://www.markhneedham.com/blog/2009/02/04/c-public-fields-vs-automatic-properties/
【讨论】:
MutableHolder<T> 类,其唯一目的是公开 T 类型的公共字段。将 Interlocked 兼容的集合项存储在集合中时,将它们包装在此类中,即使集合不支持此类内容,也可以对它们使用 Interlocked 方法,并且在此类中包装值类型将允许它们可以“直接”更改而不修改基础集合。通过使用暴露字段 PODS 作为类型参数,可以在类对象中保存多个项目。
如果您的编译器不优化 getter 和 setter 调用,则访问您的属性可能比读取和写入字段(调用堆栈)更昂贵。如果您执行很多很多调用,这可能是相关的。
但是,老实说,我不知道哪一种语言是正确的。至少在 .NET 和 Java 中,这都得到了很好的优化。
从设计的角度来看,我不知道推荐使用字段的情况...
干杯 马蒂亚斯
【讨论】:
如果您有一个需要公开的常量,您不妨将其设为公开字段,而不是为其创建 getter 属性。
除此之外,就良好的 OOP 原则而言,我认为没有必要。
他们在那里并且被允许,因为有时您需要灵活性。
【讨论】: