在什么情况下应该使用公共字段而不是属性?
可能的重复:
公共数据成员与 Getters、Setters
在什么情况下应该使用公共字段,而不是属性或 getter 和 setter 方法(不支持属性)?到底在哪里推荐使用它们,为什么,或者,如果不推荐,为什么仍然允许它们作为语言功能?毕竟,它们打破了面向对象的封装原则,其中允许并鼓励 getter 和 setter。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
如果您有一个需要公开的常量,您不妨将其设为公共字段,而不是为其创建 getter 属性。
除此之外,就良好的 OOP 原则而言,我认为没有必要。
它们在那里并且被允许,因为有时你需要灵活性。
If you have a constant that needs to be public, you might as well make it a public field instead of creating a getter property for it.
Apart from that, I don't see a need, as far as good OOP principles are concerned.
They are there and allowed because sometimes you need the flexibility.
这很难说,但在我看来,公共字段仅在使用结构时才有效。
但不同的人有不同的想法:
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/
That's hard to tell, but in my opinion public fields are only valid when using structs.
But different people have different thoughts about:
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/
如果您的编译器没有优化 getter 和 setter 调用,则对属性的访问可能比读取和写入字段(调用堆栈)更昂贵。如果您执行很多很多调用,这可能是相关的。
但是,说实话,我不知道任何语言都可以表达出这一点。至少在 .NET 和 Java 中这都得到了很好的优化。
从设计的角度来看,我不知道建议使用字段的情况......
干杯
马蒂亚斯
If your compiler does not optimize getter and setter invocations, the access to your properties might be more expensive than reading and writing fields (call stack). That might be relevant if you perform many, many invocations.
But, to be honest, I know no language where this is true. At least in both .NET and Java this is optimized well.
From a design point of view I know no case where using fields is recommended...
Cheers
Matthias
让我们首先看一下这个问题为什么我们需要访问器(getter/setter)?您需要它们能够在分配新值/读取值时覆盖行为。您可能想要添加缓存或返回计算值而不是属性。
你的问题现在可以形成为我总是想要这种行为吗?我可以想到这根本没有用的情况:结构(什么是C中的
struct
) 。传递 参数对象 或包装多个值的类以插入到 Collection 是实际上不需要访问器的情况:对象只是变量的容器。Let's first look at the question why we need accessors (getters/setters)? You need them to be able to override the behaviour when assigning a new value/reading a value. You might want to add caching or return a calculated value instead of a property.
Your question can now be formed as do I always want this behaviour? I can think of cases where this is not useful at all: structures (what were
struct
s in C). Passing a parameter object or a class wrapping multiple values to be inserted into a Collection are cases where one actually does not need accessors: The object is merely a container for variables.使用 get 而不是 public 字段的原因只有一个(*):惰性求值。即您想要的值可能存储在数据库中,或者可能需要很长时间才能计算,并且不希望您的程序在启动时初始化它,而是仅在需要时初始化它。
使用 set 而不是 public 字段的原因只有一个(*):其他字段的修改。即,当目标字段的值更改时,您也会更改其他字段的值。
强制在每个字段上使用 get 和 set 与 YAGNI 相矛盾原则。
如果你想公开对象的字段值,那就公开它!创建一个具有四个独立字段的对象并要求所有字段都使用 get/set 或属性访问是完全没有意义的。
*:其他原因(例如可能的数据类型更改)是毫无意义的。事实上,无论您在何处使用
a = o.get_value()
而不是a = o.value
,如果您更改get_value()
返回的类型code> 每次使用时都必须更改,就像更改value
的类型一样。There is one single reason(*) why to use get instead of public field: lazy evaluation. I.e. the value you want may be stored in a database, or may be long to compute, and don't want your program to initialize it at startup, but only when needed.
There is one single reason(*) why to use set instead of public field: other fields modifications. I.e. you change the value of other fields when you the value of the target field changes.
Forcing to use get and set on every field is in contradiction with the YAGNI principle.
If you want to expose the value of a field from an object, then expose it! It is completely pointless to create an object with four independent fields and mandating that all of them uses get/set or properties access.
*: Other reasons such as possible data type change are pointless. In fact, wherever you use
a = o.get_value()
instead ofa = o.value
, if you change the type returned byget_value()
you have to change at every use, just as if you would have changed the type ofvalue
.主要原因与 OOP 封装无关(尽管人们经常这么说),而与版本控制有关。
事实上,从 OOP 的立场来看,人们可能会认为字段比“盲目”属性更好,因为缺乏封装比假装封装然后将其吹走的东西更清楚。如果封装很重要,那么最好看看它何时不存在。
从外部看,名为 Foo 的属性与名为 Foo 的公共字段的处理方式不同。在某些语言中,这是显式的(该语言不直接支持属性,因此您有 getFoo 和 setFoo),而在某些语言中,这是隐式的(C# 和 VB.NET 直接支持属性,但它们不与二进制兼容)如果将字段更改为属性,则编译为使用字段的字段和代码将会中断,反之亦然)。
如果您的 Foo 只是对底层字段进行“盲”设置和写入,那么目前与暴露该字段相比,没有封装优势。
但是,如果以后需要利用封装来防止无效值(您应该始终防止无效值,但也许您在第一次编写类时没有意识到某些无效值,或者“有效”可能已更改为范围更改),包装记忆评估,触发对象中的其他更改,触发更改事件,防止昂贵的不必要的等效集等等,那么您无法在不破坏正在运行的代码的情况下进行更改。
如果该类是相关组件的内部类,则这不是问题,并且如果字段在一般 YAGNI 原则下可以合理读取,我会说使用字段。然而,YAGNI 在跨组件边界方面表现得不太好(如果我确实需要我的组件今天工作,我当然am可能需要它明天在您更改组件后工作)我的取决于),因此抢先使用属性是有意义的。
The main reason is nothing to do with OOP encapsulation (though people often say it is), and everything to do with versioning.
Indeed from the OOP position one could argue that fields are better than "blind" properties, as a lack of encapsulation is clearer than something that pretends to encapsulation and then blows it away. If encapsulation is important, then it should be good to see when it isn't there.
A property called Foo will not be treated the same from the outside as a public field called Foo. In some languages this is explicit (the language doesn't directly support properties, so you've got a getFoo and a setFoo) and in some it is implicit (C# and VB.NET directly support properties, but they are not binary-compatible with fields and code compiled to use a field will break if it's changed to a property, and vice-versa).
If your Foo just does a "blind" set and write of an underlying field, then there is currently no encapsulation advantage to this over exposing the field.
However, if there is a later requirement to take advantage of encapsulation to prevent invalid values (you should always prevent invalid values, but maybe you didn't realise some where invalid when you first wrote the class, or maybe "valid" has changed with a scope change), to wrap memoised evaluation, to trigger other changes in the object, to trigger an on-change event, to prevent expensive needless equivalent sets, and so on, then you can't make that change without breaking running code.
If the class is internal to the component in question, this isn't a concern, and I'd say use fields if fields read sensibly under the general YAGNI principle. However, YAGNI doesn't play quite so well across component boundaries (if I did need my component to work today, I certainly am probably going to need that it works tomorrow after you've changed your component that mine depends on), so it can make sense to pre-emptively use properties.