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

时间:2021-04-15 22:26:10

Note: C++ specific question

I personally find it weird/ugly when a class uses a getter to access its own member data. I know the performance impact is none but I just don't like to see all those method calls. Are there any strong arguments either way, or is it just one of those things that's personal preference and should be left to each coder, or arbitrarily controlled in a coding standard?

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

Update: I'm meaning simple getters, specifically for a class' non-public members.

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

10 个解决方案

#1


12  

Willingness to use getters/setters within class member implementation is the canary in the mine telling that your class is growing unreasonably. It tells that your class is trying to do too many different things, that it serves several purposes where it should serve one instead.

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

In fact, this is usually encountered when you are using one part of your class to store or access your data, and another part to make operations on it. Maybe you should consider using a standalone class to store and give access to your data, and another one to provide a higher view, with more complex operations with your data.

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

#2


11  

The reason you might want to use a getter/setter is because it conceals the implementation. You won't have to rewrite all of your code if you are using getters/setters in case the implementation does change, because those members can continue to work.

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

EDIT based on the many clever comments:

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

As for a class using setters and getters on itself, that may depend on the particulars. After all, the implementation of a particular class is available to the class itself. In the cases where a class is normally instantiated, the class should use the member values directly for its own members (private or otherwise) and its parent classes (if they are protected) and only use getters/setters in the case that those members are private to the parent class.

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

In the case of an abstract type, which will usually not contain any implementation at all, it should provide pure virtual getters and setters and use only those in the methods it does implement.

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

#3


7  

THE OBVIOUS

getters and setters for protected members makes as much sense as for public... derived classes are just another form of client code, and encapsulating implementation details from them can still be useful. I'm not saying always do it, just to weight pros and cons along the normal lines.

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

getters and setters for private members is rarely a net benefit, though:

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

  • it does provide the same kind of encapsulation benefits

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

    • single place for breakpoints/logging of get/set + invariant checks during dev (if used consistently)
    • 在开发期间断点/记录get / set +不变检查的单个位置(如果一致地使用)

    • virtual potential
    • etc...

    but only to the presumably relatively small implementation of the same struct/class. In enterprise environments, and for public/protected member data, those benefits can be substantial enough to justify get/set methods: a logging function may end up having millions of lines of code depedent on it, and hundreds or thousands of libraries and apps for which a change to a header may trigger recompilation. Generally a single class implementation shouldn't be more than a few hundred (or at worst thousand) lines - not big or complex enough to justify encapsulating internal private data like this... it could be said to constitute a "code smell".

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

THE NOT-SO OBVIOUS

不太可能

  • get/set methods can very occasionally be more readable than direct variable access (though more often less readable)
  • get / set方法偶尔比直接变量访问更具可读性(尽管通常不太可读)

  • get/set methods may be able to provide a more uniform and convenient interface for code-generated member or friend methods (whether from macros or external tools/scripts)
  • get / set方法可能能够为代码生成的成员或朋友方法(无论是来自宏还是外部工具/脚本)提供更加统一和方便的界面

  • less work required to transition between being a member or friend to a freestanding helper function should that become possible
  • 如果成为可能,在成为会员或朋友之间转换为独立帮助功能所需的工作量减少

  • implementation may be rendered more understandable (and hence maintainable) to people who're normally only users of the class (as more operations are expressed via, or in the style of, the public interface)
  • 对于通常只是该类用户的人(因为更多操作通过公共接口或以公共接口的方式表达),可以使实现更容易理解(并因此可维护)

It's a bit out of scope for the question, but it's worth noting that classes should generally provide action-oriented commands, event-triggered callbacks etc. rather than encouraging a get/set usage pattern.

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

#4


4  

It seems most people didn't read your question properly, the question is concerning whether or not class methods accessing its own class' members should use getters and setters; not about an external entity accessing the class' members.

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

I wouldn't bother using getter and setter for accessing a class' own members.

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

However, I also keep my classes small (typically about 200-500 lines), such that if I do need to change the fields or change its implementations or how they are calculated, search and replace wouldn't be too much work (indeed, I often change variable/class/function names in the early development period, I'm picky name chooser).

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

I only use getter and setters for accessing my own class members when I am expecting to change the implementation in the near future (e.g. if I'm writing a suboptimal code that can be written quickly, but plans to optimize it in the future) that might involve radically changing the data structure used. Conversely, I don't use getter and setter before I already have the plan; in particular, I don't use getter and setter in expectation of changing things I'm very likely never going to change anyway.

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

For external interface though, I strictly adhere to the public interface; all variables are private, and I avoid friend except for operator overloads; I use protected members conservatively and they are considered a public interface. However, even for public interface, I usually still avoid having direct getters and setters methods, as they are often indicative of bad OO design (every OO programmers in any language should read: Why getter and setter methods are Evil). Instead, I have methods that does something useful, instead of just fetching the values. For example:

对于外部接口,我严格遵守公共接口;所有变量都是私有的,除了运算符重载之外,我避免使用朋友;我保守地使用受保护的成员,他们被认为是一个公共接口。然而,即使对于公共接口,我通常仍然避免使用直接的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();
}

#5


3  

The only advantage is that it allows changing internal representation without changing external interface, permitting lazy evaluation, or why not access counting.

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

In my experience, the number of times I did this is very, very low. And it seems you do, I also prefer to avoid the uglyness and weightyness of getter/setters. It is not that difficult to change it afterwards if I really need it.

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

As you speak about a class using its own getter/setters in its own implementation functions, then you should consider writing non-friend non-member functions where possible. They improve encapsulation as explained here.

当您在自己的实现函数中使用自己的getter / setter来讨论类时,您应该考虑尽可能编写非朋友非成员函数。如本文所述,它们改善了封装。

#6


2  

An argument in favor of using getters is that you might decide one day to change how the member field is calculated. You may decide that you need it to be qualified with some other member, for instance. If you used a getter, all you have to do is change that one getter function. If you didn't you have to change each and every place where that field is used currently and in the future.

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

#7


2  

Just a crude example. Does this help?

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

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(){}

EDIT:

I would say that it depends. In case the getters do some kind of validation, it is better to go through the validation even if it means the class members being subjected to that validation. Another case where going through a common entry point could be helpful is when the access needs to be essentially in a sequential and synchronized manner e.g. in a multithreaded scenario.

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

#8


2  

this is actually for supporting the object oriented-ness of the class by abstracting the way to get(getter). and just providing its easier access.

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

#9


1  

Protecting a member variable by wrapping its access with get/set functions has its advantages. One day you may wish to make your class thread-safe - and in that instance, you'll thank yourself for using those get/set functions

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

#10


1  

Simple answer. If you are writing a one shoot program, that will never change, you can leave the getters at peace and do without any.

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

However if you write a program that could change or been written over time, or others might use that code, use getters.

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

If you use getters it helps change the code faster later on, like putting a guard on the property to verify correctness of value, or counting access to the property(debugging).

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

Getters to me are about easy possibilities(free lunch). The programmer who write the code does not need getters, he wants them.

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

hope that help.

希望有所帮助。

#1


12  

Willingness to use getters/setters within class member implementation is the canary in the mine telling that your class is growing unreasonably. It tells that your class is trying to do too many different things, that it serves several purposes where it should serve one instead.

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

In fact, this is usually encountered when you are using one part of your class to store or access your data, and another part to make operations on it. Maybe you should consider using a standalone class to store and give access to your data, and another one to provide a higher view, with more complex operations with your data.

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

#2


11  

The reason you might want to use a getter/setter is because it conceals the implementation. You won't have to rewrite all of your code if you are using getters/setters in case the implementation does change, because those members can continue to work.

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

EDIT based on the many clever comments:

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

As for a class using setters and getters on itself, that may depend on the particulars. After all, the implementation of a particular class is available to the class itself. In the cases where a class is normally instantiated, the class should use the member values directly for its own members (private or otherwise) and its parent classes (if they are protected) and only use getters/setters in the case that those members are private to the parent class.

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

In the case of an abstract type, which will usually not contain any implementation at all, it should provide pure virtual getters and setters and use only those in the methods it does implement.

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

#3


7  

THE OBVIOUS

getters and setters for protected members makes as much sense as for public... derived classes are just another form of client code, and encapsulating implementation details from them can still be useful. I'm not saying always do it, just to weight pros and cons along the normal lines.

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

getters and setters for private members is rarely a net benefit, though:

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

  • it does provide the same kind of encapsulation benefits

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

    • single place for breakpoints/logging of get/set + invariant checks during dev (if used consistently)
    • 在开发期间断点/记录get / set +不变检查的单个位置(如果一致地使用)

    • virtual potential
    • etc...

    but only to the presumably relatively small implementation of the same struct/class. In enterprise environments, and for public/protected member data, those benefits can be substantial enough to justify get/set methods: a logging function may end up having millions of lines of code depedent on it, and hundreds or thousands of libraries and apps for which a change to a header may trigger recompilation. Generally a single class implementation shouldn't be more than a few hundred (or at worst thousand) lines - not big or complex enough to justify encapsulating internal private data like this... it could be said to constitute a "code smell".

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

THE NOT-SO OBVIOUS

不太可能

  • get/set methods can very occasionally be more readable than direct variable access (though more often less readable)
  • get / set方法偶尔比直接变量访问更具可读性(尽管通常不太可读)

  • get/set methods may be able to provide a more uniform and convenient interface for code-generated member or friend methods (whether from macros or external tools/scripts)
  • get / set方法可能能够为代码生成的成员或朋友方法(无论是来自宏还是外部工具/脚本)提供更加统一和方便的界面

  • less work required to transition between being a member or friend to a freestanding helper function should that become possible
  • 如果成为可能,在成为会员或朋友之间转换为独立帮助功能所需的工作量减少

  • implementation may be rendered more understandable (and hence maintainable) to people who're normally only users of the class (as more operations are expressed via, or in the style of, the public interface)
  • 对于通常只是该类用户的人(因为更多操作通过公共接口或以公共接口的方式表达),可以使实现更容易理解(并因此可维护)

It's a bit out of scope for the question, but it's worth noting that classes should generally provide action-oriented commands, event-triggered callbacks etc. rather than encouraging a get/set usage pattern.

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

#4


4  

It seems most people didn't read your question properly, the question is concerning whether or not class methods accessing its own class' members should use getters and setters; not about an external entity accessing the class' members.

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

I wouldn't bother using getter and setter for accessing a class' own members.

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

However, I also keep my classes small (typically about 200-500 lines), such that if I do need to change the fields or change its implementations or how they are calculated, search and replace wouldn't be too much work (indeed, I often change variable/class/function names in the early development period, I'm picky name chooser).

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

I only use getter and setters for accessing my own class members when I am expecting to change the implementation in the near future (e.g. if I'm writing a suboptimal code that can be written quickly, but plans to optimize it in the future) that might involve radically changing the data structure used. Conversely, I don't use getter and setter before I already have the plan; in particular, I don't use getter and setter in expectation of changing things I'm very likely never going to change anyway.

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

For external interface though, I strictly adhere to the public interface; all variables are private, and I avoid friend except for operator overloads; I use protected members conservatively and they are considered a public interface. However, even for public interface, I usually still avoid having direct getters and setters methods, as they are often indicative of bad OO design (every OO programmers in any language should read: Why getter and setter methods are Evil). Instead, I have methods that does something useful, instead of just fetching the values. For example:

对于外部接口,我严格遵守公共接口;所有变量都是私有的,除了运算符重载之外,我避免使用朋友;我保守地使用受保护的成员,他们被认为是一个公共接口。然而,即使对于公共接口,我通常仍然避免使用直接的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();
}

#5


3  

The only advantage is that it allows changing internal representation without changing external interface, permitting lazy evaluation, or why not access counting.

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

In my experience, the number of times I did this is very, very low. And it seems you do, I also prefer to avoid the uglyness and weightyness of getter/setters. It is not that difficult to change it afterwards if I really need it.

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

As you speak about a class using its own getter/setters in its own implementation functions, then you should consider writing non-friend non-member functions where possible. They improve encapsulation as explained here.

当您在自己的实现函数中使用自己的getter / setter来讨论类时,您应该考虑尽可能编写非朋友非成员函数。如本文所述,它们改善了封装。

#6


2  

An argument in favor of using getters is that you might decide one day to change how the member field is calculated. You may decide that you need it to be qualified with some other member, for instance. If you used a getter, all you have to do is change that one getter function. If you didn't you have to change each and every place where that field is used currently and in the future.

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

#7


2  

Just a crude example. Does this help?

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

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(){}

EDIT:

I would say that it depends. In case the getters do some kind of validation, it is better to go through the validation even if it means the class members being subjected to that validation. Another case where going through a common entry point could be helpful is when the access needs to be essentially in a sequential and synchronized manner e.g. in a multithreaded scenario.

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

#8


2  

this is actually for supporting the object oriented-ness of the class by abstracting the way to get(getter). and just providing its easier access.

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

#9


1  

Protecting a member variable by wrapping its access with get/set functions has its advantages. One day you may wish to make your class thread-safe - and in that instance, you'll thank yourself for using those get/set functions

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

#10


1  

Simple answer. If you are writing a one shoot program, that will never change, you can leave the getters at peace and do without any.

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

However if you write a program that could change or been written over time, or others might use that code, use getters.

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

If you use getters it helps change the code faster later on, like putting a guard on the property to verify correctness of value, or counting access to the property(debugging).

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

Getters to me are about easy possibilities(free lunch). The programmer who write the code does not need getters, he wants them.

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

hope that help.

希望有所帮助。