什么是更好的做法?保护/吸气?

时间:2011-11-20 12:45:43

标签: c++ oop

如果我有一个继承自另一个类的类,并且只有这个类必须使用某个变量,这是更好的做法吗?让所述变量在基类中被“保护”,或者将其变为私有并为其提供受保护的getter?

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

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

是否有任何资源可以教会我如何构建代码?

6 个答案:

答案 0 :(得分:2)

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

  • 如果不是,请使用该字段。
  • 如果是,请使用getter。

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

顺便说一句,C#和Java等托管语言通常需要存在getter,其中“逻辑”只是普通字段就足够了,因为他们的UI设计(和其他)工具被实现为使用{{3} } 那样。所以过度使用getter的做法似乎已经“擦掉”了C ++,尽管C ++中没有反射或这样的工具。

答案 1 :(得分:2)

protectedpublic更接近private。人们可以创建派生类,访问和更改受保护成员,并将其派生实例用作基类的实例。您可以根据这个做出决定。如果您希望数据成员对外部世界是只读的,那么您需要一个getter并且无法解决这个问题。受保护的getter(也许是setter)也可以工作。

另外需要注意的是,setter可以充当数据的网关。它们可用于验证范围并在需要时抛出异常。考虑到这一点。

此外,由于您说它是供某个派生类使用的,因此您可能希望创建该类friend。这可能是也可能不是一个好主意,你应该仔细评估利弊。

我不认为吸气剂和制定者通常是糟糕的设计。我敢肯定他们可以被滥用,几乎任何成语或模式。推广从来都不是一个好主意。(1)

(1)是的。

答案 2 :(得分:1)

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

这可能是您破解的自己代码中的一行。在您自己的代码库中可能有数百个类。如果您在某种程度上公开发布了代码,那么您可能会从数百名您从未听说过且永远不会遇到的程序员那里打破数千行代码。

有时这种休息是必要且好的。有时可以通过一点远见来避免它。养成理解并考虑变革原因的习惯是良好设计的核心。

  

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

Getters和Setters只为您提供少量封装。你仍然没有从用户那里隐藏太多东西。他们仍然知道你的代码中有一个这种类型的字段(或者至少知道你假装存在那个字段),并且它们依赖于它存在。如果您以不必要的方式更改了类的实现,则除非您愿意中断所有相关代码,否则无法删除getter / setter。如果你试图避免中断,你必须让这些访问者仍然有效并且具有逻辑意义,这可能很难。

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

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

有时直接暴露一个字段,而不是使用getter / setter是有道理的。有时,完全由字段构成的“类”是有意义的(考虑使用struct代替)。这在非常低级别的代码(例如从数据中提取数据的代码)或在另一个类的实现内部(例如在算法的实现中)中最常见。通常,您会将这些类隐藏在其他类中,因此代码的用户永远不会看到它们。

  

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

一揽子陈述通常对他们有道理,但事实很少是二元的。

养成问“为什么?”的习惯。养成为自己判断真相的习惯,并在自己的背景下判断情境。有时在特定情况下,“总是最好的”实际上并不是最好的,甚至是不可取的。

答案 3 :(得分:0)

在大多数情况下,getter和setter确实显示出糟糕的设计。但是没有一般规则。使用getter和setter的主要原因应该是调试,所以当你从派生类访问某个基类成员时,你可以设置一个断点来拦截对该成员的更改。

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

答案 4 :(得分:0)

如果不需要在派生类之外访问Base类中的成员,那么在基类中创建它们protected。这是protected访问说明符的目的。

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

答案 5 :(得分:0)

什么是课程? 数据的集合或行为的集合

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

<强>字段

  • 是数据吗
  • 你不能在不改变依赖类的情况下改变他们的行为(除非他们指向abstract base classes
  • 可以使用运算符直接访问它们,因此可以在表达式中内联使用。
  • 你不能用基于名词的名字变得聪明。他们通常不会被束缚于行为。

访问者方法

  • 是行为
  • 您可以更改它们而无需更改依赖类(假设您保持相同contract
  • 您不能直接使用运算符访问它们,因此不能直接在尽可能多的表达式中使用它们(没有一些工作)。
  • 您可以与他们一起Method Chaining
  • 您可以使用基于动词的名称(GetCreateFind等方式获得您想要的聪明。他们定义了一种行为。

Tangent:方法链接很整洁,因为它可以让你创建一个名为a "Fluent Interface"的东西。

<强>封装

无论你做什么,你都应该记住你的OO原则。请勿违反encapsulation

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

您班级的情况属实,取决于该班级的level of abstraction

何时使用

在某些情况下使用它们都是有意义的。

在较低级别的代码中,与数据更紧密,更紧密地协作是有意义的。在这些情况下,您应该使用性能最高,数据最多的语法。 使用字段

更高级别的代码更有意义地与行为密切合作。在这些情况下,您应该使用最灵活且最符合行为的语法。 使用访问者。或者,通常不使用访问者。改为使用接口,类和非访问器方法。

如果有疑问,我选择灵活性而非性能。通过在这个特定的细节层面上检查事物,很难预测整个程序中的性能瓶颈。我们真的很糟糕,这就是为什么有分析师存在的原因。将访问器设置为字段比反之亦然更容易。如果你小心翼翼并且很幸运,你可能已经将你的访问者内联,这将使它成为一个没有实际意义的点。