这是在“北京设计模式学习小组”里讨论的一个问题,关于是否可以直接公开类的属性字段?问题起源于对单例模式的讨论。由于行文的流畅和理解的必要,这里作了一些整理。
【注:因为担心涉及到隐私,这里未公开各位发言者的昵称和QQ号。也未向各位发言者征求是否同意被引用的请求。若您看到帖子后觉得有不妥之处,请在评论处留言,我会及时联系您并作出相应处理 。谢谢!】
Y: 如果把一个非单例的概念弄成一个单例设计,回退起来是很痛苦的,反过来还好处理一些。单例确实就是全局变量,是良好命名过的全局变量
HW:一般我都直接静态字段
Y:直接暴露字段是极其不好的,这不需要理由解释
W:写getter和setter与直接暴露没有区别不暴露字段用反射也一样能访问
Y: 你说的简单数据结构,不包含行为的类是例外
W: 所以字段是否暴露不取决于安全性而是取决于可读性
Y: 代码不是用来破坏,而是用来维护的
W: 我说这个的意思也是为了说明,类的成员是否公开主要应该取决于可读性,而不是安全性比如person.age与person.getAge()相比我更倾向于公开
Y: person.age与person.getAge()如果你硬觉得前者比后者有可读性的话,我不反对
e5Max:
支持!
我想你的意思可能是说,如果一个类除了setter 和getter 之外没有别的方法,那么还不如直接将成员变量公开。
W: 是这个意思
Y: person.age与person.getAge() 后者比前者具有可维护性, 如果你的Person里有一个生日属性,那么将来你可能会重新设计Age。 而用了前者,你就没得设计
W: 你可以参照 playframework.org的开源项目orm早就放弃了hibernate的getter/setter 而是全用属性变量
Y:
不要公开字段,尽量...
HW: 所以说不要随便公开类里的方法或属性
W: 代码可读性大为提高关于age那个增加生日后去掉age字段变为age()方法
HW: 你可以做个结构体或静态工具类
W: 而不是用get
e5Max: 《C++沉思录》里面就有一个例子说明什么时候可以将成员公开,—— 这是作者C++实用主义的主张!
HW:
有时候模式是会变成反模式的
有重构解决设计问题
先用静态变量
不对 是属性
然后以后需要的话重构就可以了
最大限度的避免过度,设计
......
Y:
有这么一个例子吗?能简要介绍下不,我忘记了,时间太久了
e5Max:
@怀化-英界尔-C
《C++沉思录》这本书确实有很多将 成员属性 定义为 public 的示例代码。
书中有一个地方也专门提及了这个问题,当然不是专门的论述。我找找,看能否发个截图看看啊。
e5Max:
没错! 但并不意味着不要!有些例外情况下还是可以的,而且也是有必要的。
以下是《C++沉思录》电子版的截图:
Y: 太好了,我的意见是你十分明确你要做的事情后,就去做,不用受别的约束,前提是你确实明确
e5Max: 对! 就是我们明确自己这样做的好处大于益处,至少不会带来任何破坏!
由此我们大概可以得出如下结论:
一、尽量不要直接暴露类的属性字段,这是极其不好的,甚至都不需要理由解释。
二、尽量但并不意味着绝对不要!
那么哪些情况下可以直接暴露类的属性字段呢?
1)简单的数据结构,不包含行为的类,例如除了setter 和 getter 之外没有别的方法,那么这种情况下直接暴露类的属性字段是可以接受的。
2)C++类的嵌套类型,对于类的嵌套类型,在不影响可读性的情况下,我们允许直接暴露它的属性字段,因为它的客户只有类本身,所以不存在访问安全性。
【关于Pimpl惯用法:Pimpl惯用法通过将私有数据和函数放入到定义在实现文件中的一个单独类型中,然后在头文件中对这个类型进行前置声明并保存一个指向该类型的指针,隐藏了相关细节内容。类的构造函数分配Pimpl类型,而析构函数则释放它。这就消除了实现细节和头文件的相关性。】
3)是否还有第三种情况?我想是有的。
总之,正如英界尔同学所说,如果你十分明确你要做的事情,就去做,不用受别的约束,前提是你确实明确。我们要明确自己这样做的好处大于益处,至少不会带来任何破坏!