繁体   English   中英

直接访问成员或始终使用getter

[英]Access members directly or always use getters

注意:C ++特定问题

当一个类使用getter访问自己的成员数据时,我个人觉得它很奇怪/丑陋。 我知道性能影响是没有但我只是不喜欢看到所有这些方法调用。 是否有任何强烈的争论,或者它只是个人喜好的事情之一,应留给每个编码人员,还是在编码标准中任意控制?

更新:我的意思是简单的吸气剂,特别是对于一个班级的非公共成员。

您可能想要使用getter / setter的原因是因为它隐藏了实现。 如果您正在使用getter / setter以防实现确实发生更改,则不必重写所有代码,因为这些成员可以继续工作。

编辑基于许多聪明的评论:

至于使用自己的吸气剂和吸气剂的类,这可能取决于具体情况。 毕竟,类本身可以使用特定类的实现。 在通常实例化类的情况下,类应该直接将成员值用于其自己的成员(私有或其他)及其父类(如果它们受到保护),并且仅在这些成员使用时使用getter / setter。私有父类。

在抽象类型的情况下,它通常根本不包含任何实现,它应该提供纯虚拟的getter和setter,并且只使用它实现的方法中的那些。

在集体成员实施中愿意使用getter / setter是矿井中的金丝雀,告诉你的班级正在不合理地增长。 它告诉你的班级正在尝试做太多不同的事情,它有几个目的,它应该服务于一个

实际上,当您使用类的一部分来存储或访问数据时,通常会遇到这种情况,而另一部分则是对其进行操作。 也许你应该考虑使用一个独立的类来存储和访问你的数据,另一个用来提供更高的视图,以及更复杂的数据操作。

显而易见

受保护成员的getter和setter与public一样有意义......派生类只是客户端代码的另一种形式,从它们封装实现细节仍然很有用。 我并不是说总是这样做,只是为了减轻正常线条的利弊。

私人成员的吸气剂和制定者很少是净收益,但是:

  • 它确实提供了相同类型的封装优势

    • 在开发期间断点/记录get / set +不变检查的单个位置(如果一致地使用)
    • 虚拟潜力
    • 等等...

    但仅限于可能相对较小的相同结构/类的实现。 在企业环境中,对于公共/受保护的成员数据,这些好处可以足以证明获取/设置方法的合理性:日志记录功能最终可能依赖于数百万行代码,以及数百或数千个库和应用程序对标头的更改可能会触发重新编译。 一般来说,单个类的实现不应该超过几百(或最差千)行 - 不足以证明封装内部私有数据的大小或复杂性......可以说它构成了“代码味道”。

不那么显眼

  • get / set方法偶尔比直接变量访问更具可读性(尽管通常不太可读)
  • get / set方法可能能够为代码生成的成员或朋友方法(无论是来自宏还是外部工具/脚本)提供更加统一和方便的界面
  • 如果可能的话,在成为成员或朋友之间转换为独立的帮助函数所需的工作量减少
  • 对于通常只是该类用户的人(因为更多操作通过公共接口或以公共接口的方式表达),可以使实现更容易理解(并因此可维护)

这个问题有点超出范围,但值得注意的是,类通常应提供面向操作的命令,事件触发的回调等,而不是鼓励获取/设置使用模式。

似乎大多数人没有正确地阅读你的问题,问题是关于访问自己班级成员的班级方法是否应该使用getter和setter; 不是关于访问班级成员的外部实体。

我不打算使用getter和setter访问类自己的成员。

但是,我也保持我的类很小(通常约200-500行),这样如果我确实需要更改字段或更改其实现或如何计算它们,搜索和替换不会太多工作(事实上,我经常在早期开发期间更改变量/类/函数名称,我是挑剔的名字选择器。

当我期望在不久的将来改变实现时,我只使用getter和setter来访问我自己的类成员(例如,如果我正在编写一个可以快速编写的次优代码,但计划将来优化它)可能涉及从根本上改变所使用的数据结构。 相反,在我已经有计划之前,我不使用getter和setter; 特别是,我不会使用getter和setter来期待改变我无论如何都不会改变的东西。

对于外部接口,我严格遵守公共接口; 所有变量都是私有的,除了运算符重载之外,我避免使用friend ; 我保守地使用protected成员,他们被认为是一个公共接口。 然而,即使对于公共接口,我通常仍然避免使用直接的getter和setter方法,因为它们通常表示不良的OO设计(任何语言的每个OO程序员都应该阅读: 为什么getter和setter方法是邪恶的 )。 相反,我有一些方法可以做一些有用的事情,而不仅仅是获取值。 例如:

class Rectangle {
    private:
        int x, y, width, height;
    public:
        // avoid getX, setX, getY, setY, getWidth, setWidth, getHeight, setHeight
        void move(int new_x, int new_y);
        void resize(int new_width, int new_height);
        int area();
}

唯一的优点是它允许在不改变外部接口的情况下改变内部表示,允许惰性评估,或者为什么不访问计数。

根据我的经验,我这样做的次数非常非常低。 而且你似乎也这样做了,我也更愿意避免吸气剂/安装者的丑陋和沉重。 如果我确实需要它,那么事后就不难改变它。

当您在自己的实现函数中使用自己的getter / setter来讨论类时,您应该考虑尽可能编写非朋友非成员函数。 他们提高封装的解释在这里

支持使用getter的一个论点是你可能决定有一天改变成员字段的计算方式。 例如,您可能决定需要它与其他成员合格。 如果你使用了一个getter,你所要做的就是改变一个getter函数。 如果不这样做,则必须更改当前和将来使用该字段的每个位置。

只是一个粗略的例子。 这有帮助吗?

struct myclass{
    int buf[10];
    int getAt(int i){
        if(i >= 0 && i < sizeof(buf)){
            return buf[i];
        }
    }

    void g(){
        int index = 0;
        // some logic
        // Is it worth repeating the check here (what getAt does) to ensure
              // index is within limits
        int val = buf[index];
    }
};

    int main(){}

编辑:

我会说这取决于。 如果getter进行某种验证,最好通过验证,即使它意味着类成员正在进行验证。 通过公共入口点的另一种情况可能是有用的,即访问需要基本上以顺序和同步的方式,例如在多线程场景中。

这实际上是通过抽象get(getter)的方式来支持类的面向对象。 并提供更容易的访问。

通过使用get / set函数包装其访问来保护成员变量有其优点。 有一天你可能希望让你的类是线程安全的 - 在这种情况下,你会感谢你使用那些get / set函数

简单回答。 如果你正在编写一个永不改变的单一拍摄程序,那么你可以让游戏者安静下来而不做任何事。

但是,如果您编写的程序可能会随时间更改或编写,或者其他人可能会使用该代码,请使用getter。

如果使用getter,它有助于以后更快地更改代码,例如在属性上设置保护以验证值的正确性,或计算对属性的访问(调试)。

吸毒者对我来说很简单(免费午餐)。 编写代码的程序员不需要getter,他想要它们。

希望有所帮助。

我的想法如下。

如果可能的话,一切都应该是静态的,恒定的和私人的。

  • 由于您需要一个要实例化的变量,这意味着您需要删除一个以上的唯一副本。

  • 因为您需要一个可修改的变量,所以删除const。

  • 由于您需要其他类访问的类/变量,因此您将删除私有。

塞特犬/吸气剂的用法 - 通用。

  • 如果该值仅由类改变并且我们想要保护它,那么Getter是可以的。 通过这种方式,我们可以检索此值的当前状态,而不会更改其值。
  • 如果您计划使用Setter提供Setter,则不应使用Getter。 此时,您只需将值转换为public即可直接修改它。 因为这是Get / Set的意图。

  • 如果你打算做更多的事情,那么Setter就没那么简单了“this.value = value”。 那么你不应该称它为“SetValue”而是描述它实际上在做什么。

  • 如果让我们说你想要在“获取”它的值之前修改一个值。 然后不要将其称为“GetValue”。 虽然你可能知道发生了什么,但这与你的意图含糊不清。 除非他们查看该函数的源代码,否则其他人不会。

  • 如果让我们说你确实只是获取/设置一个值,但你正在做某种形式的安全性。 即大小检查,空检查等。这是一种替代方案。 但是你仍然应该澄清,在名称为“SafeSetValue”,“SafeGetValue”或类似“printf”的名称中有“printf_s”。

获取/设置情况的替代方案

  • 我个人拥有的一个例子。 您可以在其中看到我如何处理Get / Set方案。 我有一个GameTime类存储各种值,每个游戏都会记录这些值的变化。

    https://github.com/JeremyDX/DX_B/blob/master/DX_B/GameTime.cpp

  • 正如您将在上面看到的,我的“GETS”实际上并不是“GETS”
    值,除非在不需要修改的小情况下。 相反,它们是我试图从中检索的值的描述
    GameTime课程。 每个值都是“静态私有”。 我不能做Const
    鉴于信息是在运行时获得的,我保留了这一点
    静态,因为没有目的有多个Timing实例。

  • 您还将看到我没有任何方法可以对任何此类数据执行“SET”,但有两个函数“Begin()”和“Tick()”都会更改这些值。 这就是应该处理所有“设置者”的方式。 基本上,“Begin()”函数重置我们常量中的所有数据和加载,我们将其设置为常量,因为这是我们在运行时检索的数据。 然后TICK()在这种情况下随着时间的推移更新特定值,因此我们有最新的信息。

  • 如果你仔细研究代码,你会发现值“ResetWindowFrameTime()”和“ElapsedFrameTicks()”。 通常我不会做这样的事情,只会将值设置为公开。 因为你会看到我正在检索值并设置值。 这是Set / Get的另一种形式,但它仍然使用适合场景的命名,并且它使用来自私有变量的数据,因此拉出另一个私有变量然后将其乘以此而不是在这里工作并拉动它是没有意义的结果。 也无需编辑其他值,然后将其重置为当前帧索引,然后检索已用帧。 当我在屏幕上打开一个新窗口时使用它,这样我就可以知道我已经查看了这个窗口多长时间并继续相应的操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM