【问题标题】:In what cases should public fields be used instead of properties? [duplicate]在什么情况下应该使用公共字段而不是属性? [复制]
【发布时间】:2011-03-30 20:51:14
【问题描述】:

可能重复:
Public Data members vs Getters, Setters

在什么情况下应该使用公共字段,而不是属性或 getter 和 setter 方法(不支持属性)?究竟在哪里推荐使用它们,为什么,或者,如果不是,为什么仍然允许它们作为语言功能?毕竟,它们打破了允许和鼓励 getter 和 setter 的面向对象的封装原则。

【问题讨论】:

    标签: oop encapsulation public-fields


    【解决方案1】:

    主要原因与 OOP 封装无关(尽管人们经常这么说),而与版本控制有关。

    确实,从 OOP 的角度来看,人们可能会争辩说字段比“盲目”属性更好,因为缺乏封装比假装封装然后将其吹走的东西更清楚。如果封装很重要,那么最好看看它什么时候不存在。

    从外部看,名为 Foo 的属性与名为 Foo 的公共字段不同。在某些语言中这是显式的(该语言不直接支持属性,因此您有 getFoo 和 setFoo),而在某些语言中是隐式的(C# 和 VB.NET 直接支持属性,但它们不是二进制兼容的如果将字段更改为属性,则使用字段和编译为使用字段的代码将中断,反之亦然。

    如果您的 Foo 只是对底层字段进行“盲目”设置和写入,那么 目前 与公开该字段相比没有封装优势。

    但是,如果以后需要利用封装来防止无效值(您应该始终防止无效值,但也许您在第一次编写类时没有意识到某些地方无效,或者可能是“有效”已随范围更改而更改),包装记忆评估,触发对象中的其他更改,触发更改事件,防止昂贵的不必要的等效集等等,那么您无法在不中断的情况下进行更改运行代码。

    如果类在相关组件的内部,这不是问题,如果字段在一般 YAGNI 原则下合理读取,我会说使用字段。然而,YAGNI 在组件边界上的表现并不那么好(如果我今天确实需要我的组件工作,我当然可能需要它在你更改组件后工作明天我的依赖),所以先发制人地使用属性是有意义的。

    【讨论】:

    • 至少在 .net 中,如果所讨论的类型是一个结构,其状态通过可以公开读取的属性/字段公开,并且可以通过构造函数进行设置,以接受任何对各自类型有效的值的组合,属性几乎没有提供封装好处,但有很大的缺点。
    【解决方案2】:

    使用 get 而不是公共字段的原因只有一个(*):惰性求值。 IE。您想要的值可能存储在数据库中,或者可能需要很长时间才能计算,并且不希望您的程序在启动时对其进行初始化,但仅在需要时进行。

    使用 set 而不是 public 字段只有一个原因(*):其他字段修改。 IE。当目标字段的值发生变化时,您会更改其他字段的值。

    在每个字段上强制使用 get 和 set YAGNI 原则相矛盾

    如果你想从一个对象中暴露一个字段的值,那就暴露它! 创建一个具有四个独立字段的对象并强制它们都使用 get/set 是完全没有意义的或属性访问。

    *:其他原因,例如可能的数据类型更改是没有意义的。事实上,无论你使用a = o.get_value()而不是a = o.value,如果你改变get_value()返回的类型,你每次使用都必须改变,就像你改变value的类型一样。

    【讨论】:

    • 我不认为 YAGNI 走得这么远,“当我们发布这个组件的更高版本时,调用代码可能不需要工作”。我很确定他们会需要它,因此您必须考虑是否需要预先将字段更改为属性,因为这样的更改会破坏调用代码。
    • 正如您所写,您非常确定。 YAGNI 告诉你,在你真正需要它之前,你不要写它。
    • 我说“非常肯定”是出于幽默价值。我 100% 确定,如果我升级一个组件并且许多其他组件停止工作,我会不高兴。我不知道我是否需要给定的更改,但如果在不破坏运行代码的情况下无法进行更改,那么 YAGNI 就会受到限制。
    【解决方案3】:

    让我们先看看问题为什么我们需要访问器(getter/setter)?您需要它们能够在分配新值/读取值时覆盖行为。您可能想要添加缓存或返回计算值而不是属性。

    您的问题现在可以形成为我总是想要这种行为吗?我可以想到这根本没有用的情况:结构(C 中的structs 是什么)。传递 parameter object 或包含要插入到 Collection 中的多个值的类是实际上不需要访问器的情况:对象只是变量的容器。

    【讨论】:

      【解决方案4】:

      这很难说,但在我看来,公共字段只有在使用结构时才有效。

      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/

      【讨论】:

      • 我在 .net 中的另一个例外是类似于 MutableHolder<T> 类,其唯一目的是公开 T 类型的公共字段。将 Interlocked 兼容的集合项存储在集合中时,将它们包装在此类中,即使集合不支持此类内容,也可以对它们使用 Interlocked 方法,并且在此类中包装值类型将允许它们可以“直接”更改而不修改基础集合。通过使用暴露字段 PODS 作为类型参数,可以在类对象中保存多个项目。
      【解决方案5】:

      如果您的编译器不优化 getter 和 setter 调用,则访问您的属性可能比读取和写入字段(调用堆栈)更昂贵。如果您执行很多很多调用,这可能是相关的。

      但是,老实说,我不知道哪一种语言是正确的。至少在 .NET 和 Java 中,这都得到了很好的优化。

      从设计的角度来看,我不知道推荐使用字段的情况...

      干杯 马蒂亚斯

      【讨论】:

        【解决方案6】:

        如果您有一个需要公开的常量,您不妨将其设为公开字段,而不是为其创建 getter 属性。

        除此之外,就良好的 OOP 原则而言,我认为没有必要。

        他们在那里并且被允许,因为有时您需要灵活性。

        【讨论】:

        • 我不确定公共常量是否总是可取的。从此时起,此类值是 API 的一部分,您可能无法轻松删除/更改它。
        猜你喜欢
        • 2015-07-10
        • 1970-01-01
        • 2010-10-13
        • 2017-08-04
        • 2017-12-09
        • 2013-12-27
        • 2010-10-18
        • 2013-08-05
        • 2010-11-19
        相关资源
        最近更新 更多