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

时间:2011-08-08 23:58:36

标签: c# java oop design-patterns

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

什么时候公开公开一个字段才有意义?

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优化了方法调用,因此性能可能不是问题。有什么想法吗? (除了字段名称的正确案例约定外)

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

11 个答案:

答案 0 :(得分:12)

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

请注意open / close principle

答案 1 :(得分:5)

什么时候公开公开字段才有意义?

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

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

答案 2 :(得分:5)

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

<强>优点

  • 代码中不那么混乱
  • 更好的表现(在某些情况下)

<强>缺点

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

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

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

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

  

总之,公共类不应该公开可变字段。公共类暴露不可变字段的危害较小,但仍然有问题。但是,有时候包私有或私有嵌套类需要公开字段,无论是可变的还是不可变的。

答案 3 :(得分:3)

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

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

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

答案 4 :(得分:3)

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

例如,请参阅:

public const double PI

在System.Math中定义。

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

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

答案 5 :(得分:2)

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

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

答案 6 :(得分:2)

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

/** 
 * 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. 这是一个极低级别的类,可能会频繁使用,并且调用开销可能会成为一个问题。是的,虚拟机在许多情况下可以执行内联,但至少对于非最终方法,即使当前没有加载子类,也可能会保留一些开销。

答案 7 :(得分:1)

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

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

答案 8 :(得分:1)

  

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

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

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

答案 9 :(得分:0)

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

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

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

答案 10 :(得分:0)

在所有其他答案中,在某些情况下,您必须在公共课程中使用公共字段。例如使用 Unity 3D。序列化器只序列化字段而不是属性(以获得更好的性能)。所以在实现你的类之前,研究你使用的库和框架是如何工作的。他们可能需要将您的某些字段设为公开才能按预期工作。