提问



使用getter和setter的优点是什么 - 只能获取和设置 - 而不是简单地使用公共字段来处理这些变量?


如果getter和setter做的不仅仅是简单的get/set,我可以非常快地解决这个问题,但我并不是100%清楚如何:


public String foo;


更糟糕的是:


private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }


而前者需要更少的样板代码。

最佳参考


实际上有许多好的理由考虑使用访问器而不是直接暴露类的字段 - 超出了封装的参数,并使未来的更改更容易。


以下是我所知道的一些原因:



  • 与获取或设置属性相关联的行为的封装 - 这允许稍后更轻松地添加其他功能(如验证)。

  • 在使用替代表示法公开属性时隐藏属性的内部表示。

  • 保护您的公共接口免受更改 - 允许公共接口在实施更改时保持不变,而不会影响现有使用者。

  • 控制属性的生命周期和内存管理(处置)语义 - 在非托管内存环境(如C ++或Objective-C)中尤为重要。

  • 为属性在运行时更改时提供调试拦截点 - 在某些语言中调试属性更改为特定值的时间和位置可能非常困难。

  • 改进了与旨在针对属性获取器/设置器进行操作的库的互操作性 - 可以想到模拟,序列化和WPF。

  • 允许继承者通过覆盖getter/setter方法来更改属性的行为和语义的语义。

  • 允许getter/setter作为lambda表达式而不是值传递。

  • getter和setter可以允许不同的访问级别 - 例如get可以是公共的,但是该集可以受到保护。


其它参考1


因为从现在起2周(几个月,几年),当你意识到你的setter需要做更多而不仅仅是设置值时,你也会意识到该属性已被直接用于其他238个类: - )

其它参考2


公共字段并不比除了返回字段并分配给它之外什么都不做的getter/setter对更差。首先,很明显(在大多数语言中)没有功能差异。任何差异必须是其他因素,如可维护性或可读性。


getter/setter对的一个常见的优点是,没有。有这样的说法,你可以改变实现,你的客户不必重新编译。据说,setters允许你添加稍后验证的功能和你的客户甚至不需要了解它。但是,向setter添加验证是对其前提条件的改变,违反了之前的合同,这很简单,你可以把任何东西放在这里,你可以在以后得到同样的东西来自吸气剂。


因此,既然您违反了合同,那么更改代码库中的每个文件都是您应该要做的事情,而不是避免。如果你避免它,你会假设所有代码都假设这些方法的合同是不同的。


如果那不应该是合同,那么接口允许客户端将对象置于无效状态。 这与封装完全相反如果该字段从一开始就无法真正设置为任何东西,为什么从一开始就没有验证呢?


这个相同的参数适用于这些传递getter/setter对的其他假设优点:如果你以后决定更改所设置的值,那么你破坏了契约。如果你在某种程度上覆盖派生类中的默认功能除了一些无害的修改(比如日志记录或其他不可观察的行为)之外,你还要破坏基类的契约。这违反了Liskov Substitutability Principle,这被视为OO的原则之一。


如果一个类对每个字段都有这些愚蠢的getter和setter,那么它就是一个没有任何不变量的类,没有契约。这真的是面向对象的设计吗?如果所有课程都是那些吸气者和制定者,那它只是一个愚蠢的数据持有者,而愚蠢的数据持有者应该看起来像愚蠢的数据持有者:


class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};


将传递getter/setter对添加到这样的类中不会增加任何值。其他类应该提供有意义的操作,而不仅仅是已经提供的字段的操作。这就是你如何定义和维护有用的不变量。



  客户:我该怎么处理这个类的对象?

   Designer :您可以读取和写入多个变量。

  客户:哦......很酷,我猜?



有理由使用getter和setter,但如果这些原因不存在,那么以假封装神的名义制作getter/setter对并不是一件好事。制作getter或setter的有效理由包括经常被提到的东西。您可以稍后进行的潜在更改,例如验证或不同的内部表示。或者值可能是客户端可读但不可写(例如,读取字典的大小),因此简单的getter是一个不错的选择。但这些原因当你做出选择时应该在那里,而不仅仅是你以后想要的潜在事物。这是YAGNI的一个例子(你不需要它)。

其它参考3


很多人都在谈论getter和setter的优点,但是我想扮演魔鬼的拥护者。现在我正在调试一个非常大的程序,程序员决定让所有的东西都搞定。这看起来不错,但它是一个逆向工程的噩梦。


假设您正在查看数百行代码,您会遇到这样的问题:


person.name = "Joe";


它是一段非常简单的代码,直到你意识到它是一个setter。现在,你遵循那个setter并发现它还设置了person.firstName,person.lastName,person.isHuman,person.hasReallyCommonFirstName,并调用了person.update() ,它将查询发送到数据库等等。哦,那就是你的内存泄漏发生的地方。


乍看之下理解本地代码是一个具有良好可读性的重要特性,因为getter和setter往往会破坏。这就是为什么我尽可能地避免使用它们,并尽量减少使用它们时所做的事情。

其它参考4


原因很多。我最喜欢的是当你需要改变行为或规范你可以在变量上设置的内容时。例如,假设您有一个setSpeed(int speed)方法。但是你想要你只能设置100的最高速度。你会做的事情如下:


public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}


现在如果您的代码中使用公共字段,然后您意识到您需要上述要求,该怎么办?尽情享受公共领域的每一次使用,而不仅仅是修改你的二传手。


我2美分:)

其它参考5


在纯粹面向对象的世界中,getter和setter是一个可怕的反模式。阅读这篇文章:Getters/Setters。邪恶。期。简而言之,它们鼓励程序员将对象视为数据结构,这种思维方式纯粹是程序性的(如COBOL或C)。在面向对象的语言中,没有数据结构,只有暴露行为的对象(不是属性/属性!)[65]


您可以在Elegant Objects的第3.5节(我关于面向对象编程的书)中找到更多关于它们的信息。[66]

其它参考6


访问器和更改器的一个优点是您可以执行验证。


例如,如果foo是公开的,我可以轻松地将其设置为null,然后其他人可以尝试在对象上调用方法。但它不再存在了!用setFoo方法,我可以确保foo从未设置为null


访问器和更改器也允许封装 - 如果你不应该在它的集合中看到它的值(可能它在构造函数中设置然后由方法使用,但从不应该被更改),它将永远不会被任何人。但是,如果您可以允许其他类查看或更改它,您可以提供适当的访问者和/或更改者。

其它参考7


取决于您的语言。你已经标记了这个面向对象而不是Java,所以我想指出ChssPly76的答案与语言有关。例如,在Python中,没有理由使用getter和setter。如果您需要更改行为,可以使用属性,该属性围绕基本属性访问包装getter和setter。如下所示:


class Simple(object):
   def _get_value(self):
       return self._value -1

   def _set_value(self, new_value):
       self._value = new_value + 1

   def _del_value(self):
       self.old_values.append(self._value)
       del self._value

   value = property(_get_value, _set_value, _del_value)

其它参考8


好吧,我只想补充一点,即使有时它们对于变量/对象的封装和安全性是必要的,如果我们想要编写一个真正的面向对象程序,那么我们需要停止过度使用附件因为有时候我们非常依赖它们而不是真的有必要,这几乎就像我们把变量公之于众一样。[67]

其它参考9


我知道有点晚了,但我认为有些人对表现很感兴趣。


我做了一点性能测试。我写了一个类NumberHolder,它拥有一个Integer。你可以通过使用getter方法读取Integer
anInstance.getNumber()或通过anInstance.number直接访问该号码。我的程序通过两种方式读取数字1,000,000,000次。该过程重复五次并打印时间。我得到了以下结果:


Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms


(时间1是直接的方式,时间2是吸气剂)


你看,吸气剂(几乎)总是快一点。然后我尝试了不同的循环次数。而不是100万,我使用了1000万和10万。
结果:


1000万次循环:


Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms


1000万次循环,时间几乎相同。
这里有10万(10万)个周期:


Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms


同样具有不同的循环量,吸气剂比常规方式快一点。我希望这对你有帮助。

其它参考10


谢谢,这真的澄清了我的想法。现在这里(差不多)10个(几乎)很好的理由不使用getter和setter:



  1. 当你意识到你需要做的不仅仅是设置和获取价值时,你可以将该字段设为私有,这将立即告诉你你在哪里直接访问它。

  2. 您在那里执行的任何验证只能是无上下文,实际上很少有验证。

  3. 您可以更改正在设置的值 - 当调用者向您传递他们[[震惊恐怖]]希望您按原样存储的值时,这绝对是一场噩梦。

  4. 你可以隐藏内部表示 - 太棒了,所以你要确保所有这些操作都是对称的吗?

  5. 您已将公共界面与表格下的更改隔离开 - 如果您正在设计界面并且不确定是否可以直接访问某些内容,那么您应该继续进行设计。

  6. 有些图书馆希望这一点,但不是很多 - 反射,序列化,模拟对象都能正常使用公共字段。

  7. 继承此类,您可以覆盖默认功能 - 换句话说,您可以通过隐藏实现但使其不一致来真正混淆调用者。



我刚离开的最后三个(N/A或D/C)......

其它参考11


除非您当前交付需要,否则不要使用getter setter I.e.如果在大多数生产应用程序系统中有任何改变请求的话,请不要过多考虑将来会发生什么。


想想简单,容易,在需要时增加复杂性。


我不会利用深刻技术知识的企业主的无知,因为我认为这是正确的,或者我喜欢这种方法。


我有大量的系统编写没有getter setter只有访问修饰符和一些方法来验证n执行业务逻辑。如果你绝对需要的话。用什么。

其它参考12


我花了很长时间考虑Java案例,我相信真正的原因是:



  1. 代码接口,而不是实现

  2. 接口仅指定方法,而不是字段



换句话说,您可以在界面中指定字段的唯一方法是提供用于编写​​新值的方法和用于读取当前值的方法。


那些方法是臭名昭着的吸气者和制定者....

其它参考13


我们使用getter和setter:




  • for reusability

  • 在编程的后期阶段执行验证



Getter和setter方法是访问私有类成员的公共接口。





封装咒语



封装口头禅是将字段设为私有,方法是公共的。



   Getter方法: 我们可以访问私有变量。

  
   Setter方法: 我们可以修改私有字段。



即使getter和setter方法没有添加新功能,我们也可以改变主意,稍后再回来制作该方法



  • 更好;

  • 更安全;和

  • 更快。






在可以使用值的任何地方,可以添加返回该值的方法。代替:


int x = 1000 - 500


使用


int x = 1000 - class_name.getValue();





以外行人的名义






假设我们需要存储Person的详细信息。 Person具有nameagesex字段。这样做涉及为nameagesex创建方法。现在,如果我们需要创建另一个人,就必须重新创建nameagesex的方法。


我们可以使用getter和setter方法创建bean class(Person),而不是这样做。所以明天我们可以在需要添加新人时创建这个Bean class(Person class)的对象(参见图)。因此,我们重用bean类的字段和方法,这要好得多。

其它参考14


它对于延迟加载很有用。假设有问题的对象存储在数据库中,除非你需要它,否则你不想去获取它。如果对象是由getter检索的,那么内部对象可以为null,直到有人要求它为止,然后你可以在第一次调用getter时获取它。


我在一个项目中有一个基页类,它从一些不同的Web服务调用中加载了一些数据,但这些Web服务调用中的数据并不总是在所有子页面中使用。所有Web服务都适用于所有子页面。的好处,开创了慢的新定义,所以如果你不需要,你就不想打网络服务。


我从公共字段移动到getter,现在getter检查缓存,如果它不在那里调用Web服务。所以稍微包装,许多Web服务调用被阻止。


因此,getter使我无法在每个子页面上弄清楚我需要什么。如果我需要它,我会打电话给吸气器,如果我还没有它,它就会找到它。


    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }

其它参考15


到目前为止我在答案中遗漏的一个方面是访问规范:



  • 对于会员,您只有一个设置和获取的访问权限规范

  • 对于制定者和获取者,您可以对其进行微调并单独定义


其它参考16


在不支持属性(C ++,Java)或需要在将字段更改为属性(C#)时重新编译客户端的语言中,使用get/set方法更容易修改。例如,将验证逻辑添加到setFoo方法将不需要更改类的公共接口。


在支持真实属性的语言(Python,Ruby,也许是Smalltalk?)中,没有必要获取/设置方法。

其它参考17


编辑:我回答了这个问题,因为有很多人在学习编程问这个问题,而且大多数答案在技术上都非常有用,但如果你是新手,它们就不那么容易理解了。我们都是新手,所以我想我会尝试一个更新手友好的答案。


两个主要的是多态性和验证。即使它只是一个愚蠢的数据结构。


让我们说我们有这个简单的类:


public class Bottle {
  public int amountOfWaterMl;
  public int capacityMl;
}


一个非常简单的类,它包含多少液体,以及它的容量(以毫升为单位)。


我这样做会发生什么:


Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacity = 1000;


好吧,你不会期望这样做,对吗?
你希望有一些理智的检查。更糟糕的是,如果我从未指定最大容量怎么办?亲爱的,我们有问题。


但是还有另外一个问题。如果瓶子只是一种容器怎么办?如果我们有几个容器,所有容器和液体都装满了怎么办?如果我们可以制作一个界面,我们可以让我们的其余程序接受那个界面,瓶子,塑料桶和各种各样的东西都可以互换。这不是更好吗?由于接口需要方法,这也是一件好事。


我们最终得到的结论是:


public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
  public void setCapcityMl(int capacityMl);
}


大!现在我们只需将Bottle更改为:


public class Bottle extends LiquidContainer {
  private int capacityMl;
  private int amountFilledMl;
  public Bottle(int capacityMl, int amountFilledMl) {
    this.capacityMl = capacityMl;
    this.amountFilledMl = amountFilledMl;
    checkNotOverFlow();
  }

  public int getAmountMl() {
    return amountFilledMl;
  }

  public void setAmountMl(int amountMl) {
     this.amountFilled = amountMl;
     checkNotOverFlow();
  }
  public int getCapacityMl() {
    return capacityMl;
  public void setCapcityMl(int capacityMl) {
    this.capacityMl = capacityMl;
    checkNotOverFlow();
  }

  private void checkNotOverFlow() {
    if(amountOfWaterMl > capacityMl) {
      throw new BottleOverflowException();
    }
}


我将把BottleOverflowException的定义留给读者作为练习。


现在注意这是多么强大。我们现在可以通过接受LiquidContainer而不是Bottle来处理代码中的任何类型的容器。这些瓶子如何处理这些东西都可能有所不同。您可以将瓶子在更改时将其状态写入磁盘,或者保存在SQL数据库或GNU上的瓶子知道还有什么。


所有这些都可以有不同的方式来处理各种各样的情绪。 Bottle只是检查它是否溢出它会抛出一个RuntimeException。但这可能是错误的做法。
(关于错误处理有一个有用的讨论,但我在这里故意保持它非常简单。评论中的人可能会指出这种简单方法的缺陷。;))


是的,似乎我们从一个非常简单的想法转变为快速获得更好的答案。


还有第三件事并不是每个人都能解决的问题:Getters和setter使用方法调用。这意味着它们看起来像其他地方的普通方法。而不是为DTO和东西提供奇怪的特定语法,你到处都有同样的东西。

其它参考18


面向对象设计的基本原则之一:封装!


它为您提供了许多好处,其中之一是您可以在幕后更改getter/setter的实现,但只要数据类型保持不变,该值的任何使用者都将继续工作。

其它参考19


从面向对象设计的角度来看,两种替代方案都可能通过削弱类的封装来破坏代码的维护。有关讨论,您可以查看这篇优秀文章:http://typicalprogrammer.com/?p=23 [68]

其它参考20


您应该在以下情况下使用getter和setter:



  • 你正在处理概念上属于某个属性的东西,但是:

    • 您的语言没有属性(或某些类似的机制,如Tcl的变量跟踪),或

    • 您的语言的财产支持对于此用例来说还不够,或

    • 您的语言(或有时是您的框架)惯用惯例鼓励此用例的获取者或制定者。




所以这很少是一般的OO问题;它是一个特定于语言的问题,针对不同的语言(以及不同的用例)有不同的答案。





从OO理论的角度来看,吸气剂和制定者是无用的。你的类的接口是它的作用,而不是它的状态。 (如果没有,你写错了类。)在非常简单的情况下,类所做的只是,例如,表示直角坐标中的一个点,*属性是界面的一部分; getters和setter只是云但是在任何非常简单的情况下,属性,吸气剂和制定者都不是interf的一部分高手。


换句话说:如果你认为你班上的消费者不应该知道你有spam属性,更不用说能够不知不觉地改变它,那么给他们一个set_spam方法是你要做的最后一件事。


*即使对于那个简单的类,您也可能不一定要允许设置xy值。如果这真的是一个类,不应该有translaterotate等方法吗?如果它只是一个类,因为你的语言没有记录/结构/命名元组,那么这不是OO的问题......





但没有人会做一般的OO设计。他们用特定的语言进行设计和实施。而在某些语言中,吸气剂和制定者远非无用。


如果您的语言没有属性,那么表示某些概念上属性但实际上是计算或验证的东西的唯一方法是通过getter和setter。


即使您的语言确实具有属性,也可能存在不足或不合适的情况。例如,如果您希望允许子类控制属性的语义,则在没有动态访问的语言中,子类不能替换属性的计算属性。


至于如果我想稍后改变我的实现怎么办?问题(在OP的问题和接受的答案中以不同的措辞重复多次):如果它确实是纯粹的实现更改,并且您从属性开始,则可以将其更改为属性而不影响接口当然,除非你的语言不支持。所以这真的只是同样的情况。


此外,遵循您正在使用的语言(或框架)的习语非常重要。如果你用C#编写漂亮的Ruby风格的代码,任何经验丰富的C#开发人员都会在阅读它之前遇到困难,这很糟糕。有些语言的约定比其他语言有更强的文化。 - 它可能不是巧合的是,Java和Python恰好有两种最强大的文化。


除了人类读者之外,还会有一些图书馆和工具,希望你们遵循这些惯例,如果你们没有把你的生活变得更加困难。将Interface Builder小部件挂钩到ObjC属性以外的任何东西,或者使用某些没有getter的Java模拟库,只是让你的生活变得更加艰难。如果这些工具对你很重要,那就别打架吧。

其它参考21


Getter和setter方法是访问器方法,这意味着它们通常是用于更改私有类成员的公共接口。您使用getter和setter方法来定义属性。您可以将getter和setter方法作为类外的属性进行访问,即使您在类中将它们定义为方法也是如此。类外的这些属性可以与类中的属性名称具有不同的名称。


使用getter和setter方法有一些优点,例如能够让您创建具有可以像属性一样访问的复杂功能的成员。它们还允许您创建只读和只写属性。


尽管getter和setter方法很有用,但是你应该注意不要过度使用它们,因为在某些情况下,它们会使代码维护变得更加困难。此外,它们还提供对类实现的访问,例如公共成员。 OOP练习不鼓励直接访问课程中的属性。


编写类时,始终鼓励您尽可能多地将实例变量设为私有,并相应地添加getter和setter方法。这是因为有几次您可能不希望让用户更改类中的某些变量。例如,如果您有一个私有静态方法来跟踪为特定类创建的实例数,那么您不希望用户使用代码修改该计数器。只有构造函数语句应该在调用时增加该变量。在这种情况下,您可以创建一个私有实例变量并仅允许计数器变量的getter方法,这意味着用户只能使用getter方法检索当前值,并且他们无法设置新值使用setter方法。在没有setter的情况下创建一个getter是一种简单的方法,可以使类中的某些变量成为只读。

其它参考22


代码进化。 private非常适合您需要数据成员保护。最终所有类都应该是一种微型程序,它具有明确定义的接口,你不能只是搞砸的内部。


也就是说,软件开发并不是要设置该类的最终版本,就像你在第一次尝试时按下一些铸铁雕像一样。当你正在使用它时,代码更像是粘土。它随着你的发展而发展并且更多地了解你正在解决的问题域。在开发过程中,类可能会相互影响而不是它们应该(你计划将因素排除在一起,合并在一起,或者分开。所以我认为辩论归结为那些不想虔诚地写作的人


int getVar() const { return var ; }


所以你有了:


doSomething( obj->getVar() ) ;


代替


doSomething( obj->var ) ;


不仅getVar()在视觉上有噪音,它给人一种错觉,gettingVar()在某种程度上是一个比实际更复杂的过程。你(作为班级作家)如何看待var的神圣性,如果它有一个通行设置者,对你班级的用户来说尤其令人困惑 - 那么你看起来就像是在把这些大门用来保护某些东西你坚持是有价值的,(var的神圣性),但即使你承认var的保护也不值得任何人进入的能力set [[无论你想要什么样的价值,你都不会偷看他们在做什么。


所以我编程如下(假设一种敏捷类型的方法 - 即当我编写的代码不知道完全它将要做什么/没有时间或经验来规划精心设计的瀑布式界面组):


1)从所有公共成员开始,获取具有数据和行为的基本对象。这就是为什么在我所有的C ++示例代码中,你会注意到我使用struct代替class到处都是。


2)当一个对象的数据成员的内部行为变得足够复杂时(例如,它喜欢以某种顺序保持内部std::list),写入访问器类型函数。因为我编程就我自己而言,我并不总是立刻设置成员private,但在课堂的演变中,成员将被提升为protectedprivate


3)完全充实并且对其内部有严格规则的类(即他们确切知道他们正在做什么,而你不是他妈的(技术术语)及其内部) class指定,默认私人成员,只允许选择少数成员public


我发现这种方法可以让我避免坐在那里,并且在课堂演变的早期阶段,当许多数据成员迁出,转移等时,他们会虔诚地写下getter/setter。

其它参考23


有一个很好的理由考虑使用访问器是没有属性继承。见下一个例子:


public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}


输出:


0
0
4

其它参考24


另一种用法(在支持属性的语言中)是setter和getter可以暗示操作是非平凡的。通常,您希望避免做任何在财产中计算成本高昂的事情。

其它参考25


Getters setters 用于实现面向对象编程的两个基本方面:



  1. 抽象

  2. 封装



假设我们有一个Employee类:


package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }


这里,全名的实现细节对用户是隐藏的,并且不能直接向用户访问,这与公共属性不同。

其它参考26


getter/setter的一个相对现代的优点是可以更容易地在标记(索引)代码编辑器中浏览代码。例如。如果要查看谁设置了成员,可以打开setter的调用层次结构。


另一方面,如果该成员是公共的,那么这些工具就不能过滤对该成员的读/写访问权限。所以你必须跋涉这个成员的所有用途。

其它参考27


此外,这是为了面向未来你的班级。特别是,从一个字段更改为一个属性是一个ABI中断,所以如果你以后确定你需要更多的逻辑而不仅仅是设置/获取字段,那么你需要打破ABI,这当然会产生任何问题其他已经针对你的课程编译。

其它参考28


我想抛出注释的想法:@getter和@setter。使用@getter,您应该能够obj=class.field但不能使用class.field=obj。使用@setter,反之亦然。使用@getter和@setter,你应该能够做到这两点。这将保留封装并通过在运行时不调用简单方法来减少时间。

其它参考29


我可以想到你不会想要一切公开的一个原因。


例如,即使是通过链变量访问(即object.item.origin.x)直接访问,也可以访问您从未打算在类之外使用的变量。


通过使大多数内容都是私有的,并且只有你想要扩展的东西,并且可能在子类中引用为受保护的东西,并且通常只有静态的最终对象作为公共,那么你可以控制其他程序员和程序可以在API中使用的内容以及它的内容可以通过使用setter和getters访问你想要程序的东西,或者实际上可能正好碰巧使用你的代码的其他程序员,可以在你的程序中修改它。