什么是更好的做法?受保护/获取?

What's better practice? Protected / getter?

本文关键字:受保护 获取 更好 什么      更新时间:2023-10-16

如果我有一个继承自另一个类的类,并且只有这个类必须使用某个变量,哪个是更好的实践?让变量在基类中被"保护",还是让它私有并给它一个受保护的getter?

我听到了相互矛盾的事情。我的老师告诉我总是要使用getter,而其他人告诉我在任何级别使用getter都会暴露出糟糕的程序设计。真正的答案是什么?我觉得两者都是不合逻辑的极端。

还有,如果getter和setter是糟糕的程序设计,为什么会这样?

有什么资源可以教我如何构建我的代码吗?

除了读取值之外,您还需要(或预计将来需要)做其他事情吗?例如:断言、锁定还是使读多态?

  • 如果没有,则使用该字段。
  • 如果是,使用getter

是否使用protected与此完全正交。

顺便说一句,像c#和Java这样的托管语言通常需要getter的存在,在"逻辑上"只要普通字段就足够了,因为它们的UI设计(和其他)工具都是这样实现的。因此,尽管c++中缺乏反射或此类工具,但过度使用getter的做法似乎已经"抹掉"了c++。

protectedprivate更接近public。人们可以创建派生类,访问和更改受保护的成员,并将其派生实例用作基类的实例。你可以在此基础上做决定。如果你想让一个数据成员对外界是只读的,你需要一个getter,而这是没有办法的。受保护的getter(也可能是setter)也可以工作。

另一件要注意的事情是,setter可以作为数据的网关。它们可用于验证范围并在需要时抛出异常。这一点也要考虑进去。

同样,由于您说它是由某个派生类使用的,您可能希望使该类为friend。这可能是个好主意,也可能不是个好主意,你应该仔细评估利弊。

我不认为getter和setter通常是糟糕的设计。我敢肯定它们会被滥用,就像几乎任何习语或模式一样。泛化从来不是个好主意(1)

<一口>(1)是的。

受保护的公共接口(类、成员、字段)是您需要保持稳定的东西。每次更改受保护和公共接口时,都有可能破坏依赖于它的任何代码。

这可能是你自己的一行代码被你破坏了。在您自己的代码库中可能有数百个类。如果你公开发布你的代码,那么你可能会破坏来自数百个你从未听说过也从未见过的程序员的数千行代码。

有时候这种休息是必要的,也是好的。有时候,只要有一点远见就可以避免。养成理解和考虑改变的原因的习惯是优秀设计的核心。

如果getter和setter是糟糕的程序设计,为什么会这样?

getter和setter只提供了少量的封装。你仍然没有对用户隐瞒太多。它们仍然知道代码中存在这种类型的字段(或者至少知道您假装存在),并且它们依赖于它的存在。如果您更改了类的实现,使该字段不再需要,则无法删除getter/setter,除非您愿意破坏所有依赖的代码。如果试图避免中断,就必须使这些访问器仍然工作并具有逻辑意义,这可能很困难。

有时公开字段(或Getter/Setter)是有意义的,即使在高级代码中也是如此。如果该字段对访问很重要,并且永远没有理由更改名称或类型(从使用您的代码的程序员的角度来看),那么以某种方式公开它可能是好的,也是最好的。

有时候在Getter/Setter中包装字段是有意义的。如果您有getter/setter,则可以更容易地添加日志记录、边界检查、线程锁/信号量和调试器断点。在c++中,定义一个需要有Getter/Setter的抽象接口也比定义一个需要有字段的接口更容易。

有时直接暴露一个字段,而不使用getter/setter是有意义的。有时完全由字段组成的"类"是有意义的(考虑使用struct代替)。这在非常低级的代码中(例如从文件中提取数据的代码)或在另一个类的实现中(例如在算法的实现中)最为常见。通常你会把这些类隐藏在其他类中,所以你代码的用户永远不会看到它们。

我的老师告诉我总是使用getter,而其他人告诉我在任何级别使用getter都会暴露出糟糕的程序设计。真正的答案是什么?我觉得两者都是不合逻辑的极端。

概括性陈述往往具有真理,但真理很少是二元的。

养成问"为什么?"的习惯。养成自己判断事实的习惯,并在他们自己的背景下判断情况。有时候,在特定的情况下,"永远最好"的东西实际上并不是最好的,甚至根本不是最好的。

什么是类。数据集合还是行为集合?

当然都是。但是,让我们对比一下字段和访问方法(getter和setter)是如何使您能够处理数据和行为的。

<

字段/strong>

  • 数据
  • 你不能在不改变依赖类的情况下改变它们的行为(除非它们是指向抽象基类的指针)
  • 可以通过操作符直接访问,因此可以在表达式中内联使用。
  • 你不能像他们的名字一样聪明。它们通常不会与行为联系在一起。

访问器方法

    <
  • 是行为/gh>
  • 你可以改变他们,而不必改变依赖类(假设你保持相同的合同)
  • 你不能用操作符直接访问它们,所以不能在那么多表达式中直接使用(不需要做一些工作)。
  • 你可以用它们做方法链接。
  • 你可以尽可能聪明地使用它们基于动词的名称(Get, Create, Find等)。它们定义了一个行为。

正切:方法链接很简洁,因为它允许你创建所谓的"流畅接口"。

封装

无论你做什么,你都应该记住你的OO原则。不要破坏你的封装。

如果您编写的类应该封装它的整个行为,但却暴露了一个字段,那么您已经破坏了封装。如果您编写了一个存储数据的类,并且具有方便的赋值/数据生成模式,恰好映射到该类上的方法,那么您就没有破坏封装。

哪种情况对你的类为真取决于类所处的抽象级别。

何时使用每个

它们在特定的上下文中都是有意义的。

在较低层次的代码中,与数据更紧密地工作是有意义的。在这些情况下,您应该使用性能最好、与数据最相关的语法。<使用字段/em>。

在更高层次的代码中,与行为更紧密地工作是有意义的。在这些情况下,您应该尽可能使用最灵活和最与行为相关的语法。使用访问器。或者,通常,不使用访问器。请使用接口、类和非访问方法。

如果有疑问,我会选择灵活性而不是性能。通过在这个特定的细节层面上检查,很难预测整个程序的性能瓶颈。我们真的不擅长这个,所以才会有侧写师存在。将访问器放入字段要比将访问器放入字段容易得多。如果您足够小心和幸运,您可能已经内联了访问器,这将使它成为一个没有意义的问题。

在大多数情况下,getter和setter确实暴露了糟糕的设计。但这并没有普遍的规律。使用getter和setter的主要原因应该是为了调试,所以当您从派生类访问某个基类成员时,您可以设置一个断点来拦截对该成员的更改。

所以,你应该适应。如果您计划有2-3层继承,最好使用受保护的成员,因为成员可以更改的地方不多。如果有更多,受保护的setter/getter可能是更好的选择——您不希望在每个可能修改基类成员的类中设置断点。

如果基类中的成员不需要在派生类之外访问,则在基类中将它们设置为protected。这就是protected访问说明符的目的。

Getter和setter方法是表明该成员变量可用的一种显式方式,通常应该使用它们将成员公开给外部实体。它们使意图清晰,但是由于您的变量只需要在派生类中访问,protected访问说明符已经清楚地表达了意图。