公共数据成员vs Getters,Setters

我目前在Qt和C ++中工作。 我有类私有数据成员和公共成员函数。 我有公开的getters和setter为class级中可用的数据成员。

现在我的问题是,如果我们的类中有数据成员的getter和setter,那么将这些数据成员设置为private是什么意思? 我同意在基类中的私人数据成员听起来合乎逻辑。 但除此之外,拥有私人成员,他们的获得者和制定者对我来说似乎不是合乎逻辑的。

或者, 我们可以把所有的variables都公开化,所以根本不需要getter和setter? 有这些好习惯吗? 我知道有私人成员确保数据抽象,但有getter和setter实际上可以很容易地访问这些variables。 任何关于这个指针是受欢迎的。

都不是。 你应该有办法做事情。 如果其中一个事件恰好与特定的内部variables相对应,那么这个variables就不会传递给你的class级用户。

私人数据是私人的,所以你可以随时replace实现(可以做完整的重build,但这是一个不同的问题)。 一旦你让精灵离开瓶子,你会发现它不可能推回去。

编辑:继评论我做了另一个答案。

我的问题在于你问的是错误的问题。 关于使用getter / setter或者有公共成员,没有最佳做法。 只有最适合你的特定对象的东西,以及它如何模拟一些特定的现实世界事物(或者在游戏的情况下可能是虚构的东西)。

就个人而言,获得者/定居者是两个邪恶中较小的一个。 因为一旦你开始制作getter / setter,人们就会停止devise对象,而不是用什么数据应该是可见的,哪些数据不应该。 对公众成员来说,情况更糟,因为这种倾向使所有的事情都变得公开。

相反,请检查对象的作用,以及对于某个对象来说意味着什么。 然后创build提供该对象的自然界面的方法。 它的自然界面涉及使用getter和setter暴露一些内部属性。 但重要的一点是,你提前想到了这个问题,并为devise合理的原因创build了getters / setters。

不,它甚至不是一样的东西。

有不同级别的保护/实现隐藏可以通过不同的方法来实现类接口:

1.公共数据成员:

  • 提供对数据成员的读取和写入(如果不是const的话)访问
  • 暴露了数据对象物理上存在的事实,并且在物理上是该类的成员(允许创build指向该数据成员的指向成员types的指针)
  • 提供对数据成员的左值访问(允许创build普通指针给成员)

2.返回一个数据的引用(可能是私有数据成员)的方法:

  • 提供对数据的读取和写入(如果不是const的话)访问
  • 暴露了数据对象在物理上存在的事实,但是并没有公开它实际上是这个类的成员(不允许创build指向数据的成员types的指针)
  • 提供对数据的左值访问(允许创build普通的指针)

3.获取和/或设置方法(可能访问私有数据成员):

  • 提供对该属性的读取和/或写入访问
  • 没有公开数据对象在物理上存在的事实,更不用说物理地存在于这个类中(不允许创build指向这个数据的指针到成员types的指针或者任何types的指针)
  • 不提供对数据的左值访问(不允许创build普通的指针)

getter / setter方法甚至不公开这个属性是由物理对象实现的事实。 也就是说,在getter / setter对后面可能没有物理数据成员。

考虑到上面的内容,看到有人声称getter和setter对与公共数据成员相同是很奇怪的。 事实上,他们没有共同之处。

当然,每种方法都有其不同之处。 例如,getter方法可能会将一个const引用返回给数据,这会将其置于(2)和(3)之间的某处。

如果每个数据项都有获取者和设置者,那么将数据保密是没有意义的。 这就是为什么有getter和setter为每个数据项是一个坏主意。 考虑std :: string类 – 它(可能)有一个getter,size()函数,并且根本没有setter。

或者考虑一个BankAccount对象 – 我们是否应该有SetBalance() setter来更改当前余额? 不,大多数银行不会感谢你执行这样的事情。 相反,我们需要ApplyTransaction( Transaction & tx )

Getters和Setter允许您将逻辑应用于私有成员的input/输出,从而控制对数据的访问(对知道其OO术语的人进行封装)。

公共variables使得你的类的数据公开给不受控制和未经validation的操作,这几乎总是不可取的。

你也必须长期考虑这些事情。 你现在可能没有validation(这就是为什么公共variables似乎是一个好主意),但是他们有可能被添加到路上。 提前添加它们会留下框架,所以重新分解更less,更不用说validation将不会破坏从属代码)。

请记住,这并不意味着每个私有variables都需要自己的getter / setter。 尼尔在他的银行业务的例子中提出了一个很好的观点,即有时候“吸气/安装者”没有意义。

公开数据。 在某些情况下,你可能需要在“getter”或者“setter”中使用逻辑,你可以将数据types改成一个代理类,该类重载operator=和/或operator T (其中T =现在重新使用)来实现必要的逻辑。

编辑:控制访问数据构成封装的想法基本是错误的。 封装就是隐藏实现的细节(一般来说!), 而不是控制对数据的访问。

封装是抽象的补充:抽象处理对象的外部可见行为,而封装处理隐藏了如何实现该行为的细节。

使用getter或setter实际上会降低抽象级别并暴露实现 – 它要求客户端代码知道这个特定类实现了逻辑上作为一对函数(getter和setter)的“数据”。 使用上面提到的代理提供了真正的封装 – 除了一个不起眼的angular落案例外,它完全隐藏了一个事实,即逻辑上是一段数据实际上是通过一对函数实现的。

当然,这需要保持在上下文中:对于某些类,“数据”根本不是一个好的抽象。 一般来说,如果您可以提供更高层次的操作而不是数据,那更好。 尽pipe如此,最有用的抽象是读写数据的类,在这种情况下,(抽象的)数据应该像其他数据一样可见。 获取或设置值可能涉及的不仅仅是简单复制比特的事实是应该从用户隐藏的实现细节。

如果你确定自己的逻辑很简单,而且在读写variables时不需要做别的事情,那么最好公开数据。 在C ++的情况下,我更喜欢使用结构而不是类来强调数据是公开的。

但是,在访问数据成员时,通常需要做其他的事情,或者你想给自己稍后添加这个逻辑的自由。 在这种情况下,获得者和制定者是个好主意。 您的更改对您的代码的客户端是透明的。

附加function的简单示例 – 每次访问variables时,您都可能需要loggingdebuggingstring。

除了封装问题(这是足够的理由)之外,当有getter / setter的时候,只要设置/访问variables就很容易设置一个断点。

在严格的实践基础上,我build议你首先让所有的数据成员都是私有的, 让他们的getter和setter成为私有的。 当你发现世界其他地方(即你的“(l)用户社区”)真正需要的时候,你可以公开适当的getter和/或setter,或者编写适当控制的公共访问器。

另外(对于Neil的好处),在debugging期间,当读取或写入特定数据成员时,有一个方便的地方挂起debugging打印以及其他操作是有用的。 用getter和setter,这很容易。 对于公共数据成员来说,后果是巨大的痛苦。

我一直认为getter和setter在大多数编程语言中是故意冗长的,特别是让你三思而后用 – 为什么你的调用者需要知道你的类的内部工作应该成为你头脑中的问题。

使用公共领域而不是获得者和制定者的理由包括:

  1. 没有非法的价值。
  2. 客户端需要编辑它。
  3. 为了能够写东西,如object.XY = Z.
  4. 要做出强有力的承诺:价值只是一种价值,没有与之相关的副作用(也不会在未来)。

根据你所使用的软件types,这些都可能是非常特殊的情况(如果你认为你遇到了一个你可能是错误的),或者它们可能会一直发生。 这真的取决于。

(来自基于价值编程的十个问题 。)

我build议你没有公共数据成员(POD结构除外)。 我也不build议你所有的数据成员都有getter和setter。 相反,为你的class级定义一个干净的公共接口。 这可能包括获取和/或设置属性值的方法,这些属性可能会作为成员variables来实现。 但是不要为所有的成员制造获得者和制定者。

这个想法是,你的接口与你的实现分开,允许你修改实现,而不需要类的用户改变他们的代码。 如果你通过getter和setter来暴露所有的东西,那么使用公共数据就没有什么改进了。

使用getter和setter将允许你修改你给用户赋值的方式。

考虑以下几点:

 double premium; double tax; 

然后,您可以使用这个premium值在整个地方编写代码来获得溢价:

 double myPremium = class.premium; 

您的规格刚刚更改,从用户的angular度来看premium + tax需要premium + tax

您必须随时修改代码中正在使用的premium价值,并向其中添加tax

如果你是这样实现它的话:

 double premium; double tax; double GetPremium(){return premium;}; 

您的所有代码都将使用GetPremium() ,您的tax变更将是一行:

 double premium; double tax; double GetPremium(){return premium + tax;}; 

返回值也影响使用getter和setter。 获取variables的值或访问私有数据成员variables是有区别的。 By-value保持完整性,通过引用或by-pointer而不是太多。

Getters和Setter的存在主要是为了让我们可以控制如何提取成员,以及如何设置。 Getters和Setter不仅仅是作为一种访问特定成员的方式存在,而是为了确保在我们尝试设置成员之前,它可能符合某些条件,或者如果我们获取它,我们可以控制我们返回的副本成员在非原始types的情况下。 总的来说,当你想要pipe理一个数据成员如何交互时,你应该尝试使用g / s'ers,否则会导致成员以特殊的方式使用。

我相信使用getter和setter只是为了获取和设置值是没有用的。 公共会员和私人会员之间没有区别。 只有当你需要以某种方式控制这些值时,或者当你认为它将来可能有用时,才使用getters和setter(添加一些逻辑不会让你编辑其余的代码)。

作为参考,阅读C ++指南(C.131)