【问题标题】:Should I always use getter/setter methods in Java classes or are there times when its okay to use public attributes? [duplicate]我应该总是在 Java 类中使用 getter/setter 方法,还是有时可以使用公共属性? [复制]
【发布时间】:2013-08-11 01:00:09
【问题描述】:

我已经编写 Java 代码大约 4 个月了。我刚开始使用介绍书的指南编写 android 游戏。在书中,它们没有封装类的任何属性。

例如

public class GameObject{
    public Vector position;
    public float angle;

    public GameObject(float angle, Vector position){
...

总是有人告诉我,封装属性是一种很好的做法:只允许通过 getter 和 setter 方法访问私有属性。

有比我更有经验的程序员能告诉我哪种方式是创建属性的“正确”编码方式吗?当然,为什么?

然后跟进:我是不是应该总是封装一个类的私有属性并提供getter和setter方法,还是有公共属性可以的情况?

【问题讨论】:

  • 我应该将私有属性与 getter 和 setter 方法或公共属性一起使用 是的,我会说你应该始终使用 getter 和 setter 方法并避免使用公共字段。
  • 如果您想知道为什么您的书会这样做(或者为什么有人会这样做),Google 建议(针对 Android 早期版本的游戏)取消 getter/setter 范例因为方法开销。现在 Android 如此先进,不鼓励这种做法。请参阅 youtube.com/watch?v=U4Bk5rmIpic,时间为 0:37:10,其中 Chris Pruett 建议使用公共字段。

标签: java android class methods attributes


【解决方案1】:

封装是面向对象编程的核心概念之一。在我看来,使用 getter 和 setter 总是很好的做法。您应该避免的一件事是让外部实体随意干扰类的内部结构。

典型示例,考虑使用dateOfBirth 参数。使用settergetter,您可以进行一个小的验证过程,以确保用户不是在未来出生,或者不可能老。您还可以使用 setter 更新一些其他字段,例如年龄。

这种次要验证还可以增强代码的可重用性,因为您无需在调用这些 getter 和 setter 的任何其他类中进行此检查。

【讨论】:

    【解决方案2】:

    如果我们把纯粹的观点放在一边,我们有两个很好的理由使用 getter 和 setter -

    1. 如果您想修改您的行为,它可以减少您将来必须做的代码更改量。考虑一下您突然需要进行的以下情况 - 验证某些输入,计算某些字段或在更改时影响其他字段,限制 get 或 set 操作的范围或使其不均匀,修改某些字段的行为继承类或以某种奇怪的方式存储字段。如果您已经有了 getter 和 setter - 这些更改除了更改本身之外不会花费您任何费用。如果没有,您将不得不修改项目中字段的所有用法。

    2. 它允许您实现需要 getter 或 setter 的接口。

    【讨论】:

      【解决方案3】:

      在大多数情况下,您不应将类视为您在外部操作的一组属性,而应将其视为为应用程序提供某些服务的实体。类的大多数属性最终都是私有的,并且没有 get 或 set 方法。

      但也有例外:例如,在某些设置中,您会发现只保存值并且本身几乎没有逻辑的类。这类类的通常规则是将字段设为私有并提供 get 和 set 方法,因为一旦您将某些内容设为 public,而其他一些类依赖于它,您就无法更改它。例如,您可能希望确保特定字段的值永远不会为空或进行一些其他验证;如果您使用 set 方法,则可以在此处添加检查,但如果该字段是公共的,则您无能为力。另一个例子:你可能想改变字段类型来做一些优化,但是如果字段是公共的,你就无能为力了。

      所有的规则都是为了打破。如果你知道你永远不需要 get 和 set 方法,那么添加它们就没有多大意义了。有些人可能会抱怨“缺乏封装”,但如果类的每个属性都可以从外部读写,那么封装在哪里?

      【讨论】:

        【解决方案4】:

        封装提供了更大的灵活性。它为您提供更多控制,隐藏实现细节。您可以在不提供 set 方法的情况下降低类的可变性。 Getter 和 setter 可以有额外的逻辑。无需更改公共 API(getter 和 setter 是公共 API 的一部分)即可更轻松地更改类实现。

        【讨论】:

          【解决方案5】:

          Accessors/getters - 用于检查实例变量值的公共方法 为了让客户端能够使用一个类,ADT 的实现者通常需要提供一个或多个公共函数,以允许用户“查看”(检查)对象的私有实例变量的当前值。这些“只读”类型的方法称为访问器函数。

          例如, TwoDice 类的两个适当的访问器函数是 getDice1() 和 getDice2(),它们可用于查找其中一个骰子的当前值。 getDice1() 的定义是:

            public int getDice1()
             {
                return dice1 ;
             }
          

          getDice2() 的定义类似。我们可以使用这些函数将第一个骰子的值存储在整数变量 valueOfDie1 中,如下所示:

             TwoDice roll = new TwoDice() ;
             int valueOfDie1 = roll.getDice1() ;
          

          在方法调用roll.getDice1()中,对象roll是当前对象(调用该方法的对象),因此将getDice1()应用于该对象将返回值roll.dice1。

          Mutators /Setters - 用于更改实例变量值的公共方法。 突变器应包括数据验证,以确保实例变量的值不超出其允许范围。 例如, TwoDice 类具有一个有趣的属性,即一旦创建了 TwoDice 对象,它的值就无法更改 - 没有提供任何公共方法来允许客户端代码这样做。这样的对象被认为是不可变的,这意味着它们一旦被创建就不能被修改。许多 Java 自己的类都具有只提供不可变对象的特性 - 两个这样的例子是 String 和 Color 类。

          类设计器通常提供所谓的 mutator 或 setter 方法,以使客户端代码能够修改对象的值。这是潜在的危险,因为它可能会损害私人数据的安全性。因此,ADT 的实现者必须提供适当的数据验证,以确保将属性(实例变量)的值正确设置在其允许值的范围内。我们的 TwoDice 类的合适的 mutator 方法是 setDice1( int n ) 和 setDice2( int n ),其中第一个的定义如下:

           public void setDice1( int n )
             {
                assert (n >= 1) && (n <= 6) : "value of dice1 out of range: " + n ;
                dice1 = n ;
             } 
          

          这里有趣的是断言的使用,如果它评估为假,则会导致程序执行被终止。

          【讨论】:

            猜你喜欢
            • 2017-10-09
            • 2013-06-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-04-10
            • 2011-09-12
            • 1970-01-01
            • 2011-08-30
            相关资源
            最近更新 更多