代码之家  ›  专栏  ›  技术社区  ›  Mr. Boy

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

  •  17
  • Mr. Boy  · 技术社区  · 14 年前

    我个人认为,当一个类使用getter访问它自己的成员数据时,这很奇怪/很难看。我知道性能没有影响,但我不喜欢看到所有这些方法调用。

    更新:我指的是简单的getter,特别是针对类' 非公开

    11 回复  |  直到 14 年前
        1
  •  13
  •   SingleNegationElimination    14 年前

    根据许多巧妙的评论进行编辑:

    至于类本身使用setter和getter,这可能取决于具体情况。毕竟,特定类的实现对类本身是可用的。在一个类通常被实例化的情况下,该类应该直接为它自己的成员(private或other)和它的父类(如果它们受到保护)使用成员值,并且只在这些成员对父类私有的情况下使用getter/setter。

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

        2
  •  12
  •   Didier Trosset    14 年前

    愿意在类成员实现中使用getters/setter的意愿是矿中的金丝雀,它告诉我们你的类正在不合理地增长。它表明你的类正在尝试做太多不同的事情,它在它应该服务的几个方面起到了作用 相反。

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

        3
  •  9
  •   Tony Delroy    14 年前

    显而易见的

    私人成员的getter和setters很少是净收益,但是:

      • 断点/获取/设置日志记录的单一位置+开发期间的不变检查(如果一致使用)
      • 虚拟电位

      但仅限于同一个结构/类的相对较小的实现。在企业环境中,对于公共/受保护的成员数据,这些好处足以证明get/set方法是正确的:一个日志记录函数最终可能会有数百万行代码依赖于它,数百或数千个库和应用程序的头更改可能会触发重新编译。一般来说,一个类的实现不应该超过几百行(最坏的情况下是几千行)-不太大或不够复杂,不足以证明像这样封装内部私有数据。。。可以说它构成了一种“代码气味”。

    • get/set方法有时可能比直接变量访问更具可读性(尽管通常可读性较差)
    • get/set方法可以为代码生成的成员或友元方法(无论是来自宏还是外部工具/脚本)提供更统一和更方便的接口
    • 在成为一个成员或朋友到一个独立的助手功能之间转换所需的工作量会减少
    • 对于通常只是类的用户的人来说,实现可以变得更容易理解(因此更易于维护)(因为更多的操作是通过公共接口或以公共接口的形式表示的)

        4
  •  5
  •   Lie Ryan Bryan    14 年前

    似乎大多数人都没有正确地阅读你的问题,问题是关于是否 类方法访问自己类的成员

    我不会费心使用getter和setter来访问类自己的成员。

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

    我只使用getter和setter来访问我自己的类成员,当我希望在不久的将来更改实现时(例如,如果我正在编写一个可以快速编写的次优代码,但计划在将来对其进行优化),这可能会从根本上改变所使用的数据结构。相反,在我有计划之前,我不会使用getter和setter;尤其是,我不使用getter和setter来期望改变一些我很可能永远都不会改变的事情。

    但是对于外部接口,我严格遵守公共接口;所有变量都是私有的,我避免使用 friend protected 成员保守,他们被认为是一个公共接口。然而,即使对于公共接口,我通常仍然避免使用直接的getter和setters方法,因为它们通常表示糟糕的OO设计(任何语言的每个OO程序员都应该阅读: Why getter and setter methods are Evil ). 相反,我有一些方法可以做一些有用的事情,而不是仅仅获取值。例如:

    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();
    }
    
        5
  •  4
  •   Didier Trosset    14 年前

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

    根据我的经验,我这样做的次数非常非常少。看来你是这么想的,我也更喜欢避免那些笨重的家伙。如果我以后改变它并不难 需要它。

    当您谈到一个类在它自己的实现函数中使用它自己的getter/setter时,您应该考虑在可能的情况下编写非友元非成员函数。如前所述,它们改进了封装 here

        6
  •  2
  •   Nathan Fellman    14 年前

        7
  •  2
  •   Chubsdad    14 年前

    只是个简单的例子。这有帮助吗?

    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执行某种类型的验证,则最好通过验证,即使这意味着类成员要接受该验证。另一种情况是,当访问需要以顺序和同步的方式(例如在多线程场景中)时,通过一个公共入口点可能会有帮助。

        8
  •  2
  •   Ashish Yadav    14 年前

    这实际上是为了通过抽象get(getter)方法来支持类的面向对象性。提供更方便的访问。

        9
  •  1
  •   user206705 user206705    14 年前

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

        10
  •  1
  •   none    14 年前

    简单的回答。如果你在写一个一次性的程序,这是永远不会改变的,你可以让他们平静下来,什么都不用做。

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

    对我来说,重要的是简单的可能性(免费午餐)。编写代码的程序员不需要getter,他需要getter。

    希望有帮助。

        11
  •  0
  •   Jeremy Trifilo    6 年前

    我的想法如下。

    • 因为你需要一个变量被实例化意味着不止一个唯一的 复制你删除静电。

    • 私人的。

    Setters/Getters的用法-通用。

    • 如果值只由类和更改,那么Getter是可以的 我们要保护它。这样我们就可以检索 这个值不会改变它的值。
    • 如果计划提供Setter,则不应使用Getter 直接修改它。因为这是Get/Set的意图。

    • 如果你打算做更多的事情而不是简单地做,那么二传手是毫无用处的 而是描述它实际在做什么。

    • “得到”它的价值。那就不要叫它“GetValue”。这是模棱两可的 尽管你可能知道发生了什么。某人

    • 如果我们假设你确实只是在获取/设置一个值,但是你确实是 做一些安全措施。一、 检查空尺寸等。。这 是另一种情况。但是,您仍然应该在 “printf”中的名称,例如“SafeSetValue”、“SafeGetValue”或类似名称

    • 我个人有一个例子。你可以看到我是如何处理 获取/设置方案。我有一个游戏时间类,可以存储所有种类

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

    • 正如你在上面看到的,我的“得到”并不是“得到”的
      值,但不需要修改的小情况除外。而是
      游戏时间类。每个值都是“Static Private”。我不能做常量

      静态的,因为没有必要使用多个计时实例。

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

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