什么时候使用公共领域是有意义的?

这是我现在有一段时间的问题:

什么时候公开公开这个领域是有意义的?

public class SomeClass() { public int backing; } 

这样做的缺点(除了激怒OOP精英)之外,如果您需要在此数据之上添加任何逻辑,则必须对API进行重大更改。 我想这就是精英主义者所关注的。

Java和C#的最佳实践一直是使用getter / setter或属性来访问字段。

 public class SomeClass() { private int backing; public int getBacking() { return backing; } public void setBacking(int v) { backing = v; } } 

C#已将其演变为具有自动属性的非常简单的语法:

 public class SomeClass() { public int Backing { get; set; } } 

懒惰我仍觉得这太长了,因为我发现自己做了很多事情。 更重要的是,我不确定我知道公共领域会更有意义。

为什么不直接将公开声明的字段视为幕后的属性(或方法)? 这样就不可能激怒去耦神灵,并且不需要打字。

 public class SomeClass() { public int backing; // The same as public int backing { get; set; } } 

对于除了包装底层字段之外什么都不做的属性,我很确定JIT优化了方法调用,因此性能可能不是问题。 有什么想法吗? (除了字段名称的正确案例约定外)

编辑:感谢所有的回复。 我觉得也许不是每个人都理解我的问题。 什么时候公共场地比房产更好? 为什么这是一个更好的选择? 如果唯一的原因是方便(减少键入和混乱),那么只要遇到公共字段,编译器就会在“引擎盖下”生成属性会有什么缺点。 基本上,创建一个真正的公共领域是不可能的(因为它们都是属性)。 这有什么不对? 谢谢。

在我看来,当你设计一个类的结构时,你应该更加关注未来的变化,并且应该始终对它们友好。 如果未来的要求需要在返回值之前执行某些逻辑而不是仅返回字段的值,则必须更改类的接口,并且库的所有用户都必须更改。 这通常会成为灾难。

请记住, 开/关原则 。

何时公开披露一个字段是否有意义?

在其他地方,私人课程如下。

 public class MyOuterClass { private class MyInnerClass { public int val ; // why bother w/boiler plate } } 

以下是公共领域的利弊摘要:

好处

  • 代码中的混乱程度较低
  • 更好的性能(在某些情况下)

缺点

  • 如果不更改API,则无法更改表示
  • 不能强制执行不变量( 除非该字段是不可变的)
  • 访问这些字段时无法执行其他操作

那么我们何时应该使用公共领域? 要看。 很明显,对于公共类来说,缺点超过了优点。 在代码中发展代码的可能问题比代码中更混乱和性能影响更小。

但是,类可以是包私有或甚至是私有嵌套,在这种情况下,代码的可能更改将被本地化。 因此,绝对可以使用公共字段。 还有一些情况下性能差异不是很小。 例如,Android开发者指南声称,在可能的情况下使用直接字段访问而不是getter / setter是一种很好的做法,因为它的速度要快几倍。

总而言之,我将引用我最喜欢的书之一,J. Bloch撰写的Effective Java,第14项:

总之,公共类不应该公开可变字段。 公共类暴露不可变字段的危害较小,但仍然有问题。 但是,有时希望package-private或private嵌套类公开字段,无论是可变的还是不可变的。

我认为当你想要组合一些变量/对象(有点像C struct )时,这是有道理的。 例如:

 class Pixel { public int x; public int y; Color c; // Other Pixel related information } 

由于没有方法,如果使用错误的值并且很好地将这些变量放在一起,则不会中断任何操作。

当公共领域是更好的选择时,其中一个场景是提供你class级的常量。

例如,请参阅:

 public const double PI 

在System.Math中定义。

这种方法很受欢迎,因为它明确告知您的类的消费者,该成员不包含任何逻辑,validation或任何其他与状态相关的操作,因此可以在您想要的任何上下文中使用。

我能想到的另一个是,当你需要类作为简单操作的容器时(或者只是将大量的参数传递给方法),例如参见System.Windows.Point 。 在大多数情况下,这些容器被建模为结构。

因此,我能给出的最佳答案是,当你通过reflection做魔术时,正如人们在利用静态类型语言时所做的那样,属性对字段有意义。 从ORM工具,映射器和绑定数据之类的东西,属性可以具有与行为角度不同的字段。

JITter不会将属性转换为字段,它可以内联它们,但我不会在所有情况下都承诺它。

对于具有非平凡复杂性的项目,很少 – 但有时 – 使用公共领域是个好主意。 想到一个例子:

 /** * A two-dimensional mathematical vector. Immutable so instances may be freely shared * without violating encapsulation. */ public class Vec2 { public final int x, y; // bunch of constructors and methods omitted } 

理由:内部表示不太可能需要更改,或者在读取xy时执行任何类型的操作。 也就是说,使用setter在这里没有任何好处。

但是它会带来一些成本:

  1. 公共最终字段将非常清楚地表明类是不可变的,有了getter,你必须信任文档注释。 (请注意,没有setter并不意味着不变,因为其他一些方法可能会分配字段)
  2. 访问向量的代码可读性稍差,因为get()不会提供有意义的语义信息,但在阅读代码时仍然必须跳过(至少在Java中,C#在这里更好)。
  3. 这是一个极低级别的类经常使用,并且调用开销可能成为一个问题。 是的,虚拟机在许多情况下可以执行内联,但至少对于非最终方法,即使当前没有加载子类,也可能会保留一些开销。

一种情况,至少在.NET中,与C API互操作。 您经常会声明C#或VB版本的Windows API结构,并且通常使用公共字段来进行这些操作,因为将字段设为私有的正常原因 – 以防止有人在背后乱搞它们 – 会破坏。 在这种情况下,你知道有些东西会改变你背后的字段 – 这就是拥有结构的全部目的!

当然,您通常不会将这些未封装的结构暴露给应用程序代码 – 您将它们视为P / Invoke模块的私有元素,因此应用程序代码仍然不会处理公共字段。

Java和C#的最佳实践一直是使用getter / setter或属性来访问字段。

我认为这是第一个问题:如果你有一个吸气剂你必须也有一个二传手。 这是个错误; 在许多情况下,setter是不必要的,因为没有真正需要修改对象的属性值,并且删除可能性简化了类。

极端的情况是根本没有变异器。 使类不可变的最后阶段永远不会直接访问可变字段值(请记住,Java final不像C ++ const )。 小值类应该是不可变的。 只有getter方法才能通过创建副本来提供对可能可变字段的安全访问(在C ++中,您只需要一个按值返回的getter)。 对于那些不需要防御性复制的字段,你可以省去getter,但是类中的某些字段可能需要getter而有些则不需要。 但这会令人困惑,

你可以在java中使用一个公共字段,然后为它添加一些逻辑,比如有一个getter,使用AspectJ,包括避免写入它,如果不是来自特定的psckage等…

虽然这是一项重大改进,但它可以加快编码速度,并且仍然为未来的改进留下了很大的空间,而不必让所有人都重写所有代码,但它并没有那么多使用,因为精英主义者是众所周知的偏执者。

回到你的问题,因为jit在使用公共字段而不是getter / setter方面没有很大的改进,并且由于IDE具有自动getter和setter生成,所以在使用getter和setter时没有真正的程序员开销。 在多年的Java编程中,我只使用了公共字段几次,并且总是最终将它们转换为getter / setter对。

Interesting Posts