Closed. This question is
opinion-based。它当前不接受答案。
想改善这个问题吗?更新问题,以便
editing this post用事实和引用来回答。
5年前关闭。
最近,我与一位同事讨论了有关getter和setter的问题,该方法使用针对公共成员指针的指针(该主题导致同一辩论中没有指针,而让getter返回引用)。我不确定该主题是否会重复,但是在寻找该主题的答案时,我发现只有三个主题(
here,
here和
here)与主题“ getters / setters vs公众成员”而没有指出辩论的方向。
因此,情况如下:
有一个类
Text
。类型为
Text
的对象始终包含另一个类型为
TextProperties
的对象(例如,大小,颜色,粗体,斜体,下划线等)。要修改属性,我想直接使用
TextProperties
-object的方法进行操作,而无需创建新对象。这最终导致吸气剂返回
TextProperties
对象的指针。
这里是一个非常简单的情况示例:
//example for TextProperties
class TextProperties
{
protected:
int m_size;
bool m_bold;
public:
bool Bold() { return this->m_bold; }
void Bold(bool bold) { this->m_bold = bold; }
int Size() { return this->m_size; }
void Size(int size) { this->m_size = size; }
TextProperties()
{
this->m_bold = false;
this->m_size = 5;
}
~TextProperties() {}
}
//example for Text
class Text
{
protected:
TextProperties* m_properties;
public:
TextProperties* Properties() { return this->m_properties; }
void Properties(TextProperties* properties) { this->m_properties = properties; }
Text()
{
this->m_properties = new TextProperties();
}
~Text()
{
delete this->m_properties;
}
}
//the usage as I want it:
int main()
{
Text* exampleText = new Text();
//easily and short a property gets changed
exampleText->Properties()->Bold(true);
delete exampleText;
}
我的同事反对这种解决方案,因为使用该解决方案时,在绕开任何设置器的同时,门被打开以替换对象(也在使用返回参考的吸气器时)。
//An example for the replacing bypassing the setter:
int main()
{
Text* exampleText = new Text();
//easily and short a property gets changed
exampleText->Properties()->Bold(true);
TextProperties* test = exampleText->Properties();
*test = *(new TextProperties());
//at this point the text wouldn't be bold
delete exampleText;
}
据我所知,唯一可能安全的解决方案(其中的对象不能用另一个替换)是返回
const
并强迫使用此类的任何人创建一个新的
TextProperties
对象以仅更改一个属性。如前所述,这种解决方案是不希望的。
//just as intimation how the other, replacing safe
//way of usage I want to avoid could look:
int main()
{
Text* exampleText = new Text();
//if needed copy-construct the object otherwise just use (default) constructor
TextProperties* newProperties = new TextProperties(exampleText->Properties());
newProperties->Bold(true);
exampeText->Properties(newProperties);
delete exampleText;
}
到目前为止的情况-现在是辩论:
我的同事接受了能够直接修改属性的目标,而不是提到他认为解决方案与公共成员没有区别。
我的观点如下:
使用getter / setter时,内部部件被隐藏(=封装)
内部更改可以更容易/更快地执行,因为公共成员访问分散在所有源代码上
也可能用丑陋的内部名称加上前缀和/或后缀来覆盖一个很好且易于描述的名称(例如,内部:int m_x,m_y <->外部:Width(),Height()(是的,人们通常会这样做))使用该类的代码更加清晰和易于理解
提供getter / setter类消费者可以确保事情以应该完成的方式完成(对我来说,public成员仅对简单类型有意义),因为更复杂的对象可能需要一些特定的操作,例如确保所包含信息的正确性)也保护该成员以防错误修改。
如果有人在绕过吸气剂的同时想替换对象,则他必须故意这样做,因此,当代码无法按预期工作时,这是他的错,这时我的任务仅包括确保不会发生损坏(但这就是无论如何一直在我的任务中)->如果您想强迫某些事情可以做...好的或坏的,这是c ++无法解决的另一个问题,它只是提供了可能性;)
当避免按值排序时,不需要复制对象,可以复制但不必复制性能(通过编辑添加点)
以可编辑方式访问对象并直接更改访问对象的成员时(对我而言)较短且可理解的源代码(通过编辑添加的点)
我认为前两点主要是经典的getter / setter与公众成员讨论的论点。无论如何,这种论点并没有改变我同事的观点,而我现在在这个问题上花了几天的时间。因此,我想知道真的没有区别(我个人肯定会说“有区别”),这些论点只是我的主观意见,是否属于个人品味的问题,确实存在更具说服力的论点(对于两者意见)还是存在完全不同的解决方案而不会引起讨论?
编辑:除了这些问题以外,我想进一步指出我的问题的重点(根据答案上的
first comment)并指定问题本身:
如果尚未决定使用getter和setter,并且还使用引用或指针破坏了getter的封装,那么为什么/应该比使该成员成为公共成员更好呢? (我试图提供具有这些getter的列表参数,并且我想知道这些参数中的哪些是in /有效的,或者哪些其他参数可以赞成/反对这些getter或public成员)
希望这不是重复的,我希望得到一些有趣的答案。谢谢! :)
如果要实现以下两个目标:
1)良好的面向对象设计。
2)完全避免内部TextProperties
对象的未经授权的更改(绕过封装)。
我建议以下解决方案:
1)定义用于获取/设置单个文本属性的接口TextPropertiesInterface
。它看起来类似于TextProperties
类。
2)实施TextPropertiesInterface
例如由Text
类中的嵌套私有类(其他可能的解决方案在文章结尾)。该实现实际上将读取/更改内部TextProperties
对象。
3)将TextPropertiesInterface
的内部实现从Text
类公开为接口的引用/指针。
这就是我在代码中看到的样子:
class TextPropertiesInterface{
public:
virtual int GetSize() = 0;
virtual void SetSize(int iSize) = 0;
virtual Color GetColor() = 0;
virtual void SetColor(Color oColor) = 0;
etc ...
}
class Text{
private:
// internal object completely protected from bypassing incapsulation
TextProperties m_Properties;
// Nested private implementation of the interface
class TextPropertiesInterfaceImpl: public TextPropertiesInterface{
TextProperties& m_Properties; // init it with Text::m_Properties
...
}
TextPropertiesInterfaceImpl m_TextPropertiesInterfaceImpl;
public:
// Exposing the interface outside
TextPropertiesInterface& Properties(){
return m_TextPropertiesInterfaceImpl;
}
};
现在,
Text
类的客户端/用户可以通过
TextObj.Properties().SetWidth(10)
这样的方式获取/设置文本属性。
外部客户端/用户无法以未经授权的方式(例如,通过替换对象等)修改内部
TextProperties
对象。
附加说明:您可以通过其他一些方式来实现
TextPropertiesInterface
,这些方式可能需要更少的代码行。
示例1:类
TextProperties
可以实现
TextPropertiesInterface
。这将消除类
TextPropertiesInterfaceImpl
,但将向
Text
类的外部客户端/用户显示一些实现细节。同样,这将允许这样的肮脏技巧:
static_cast<TextProperties&>(TextObj.Properties())
绕过封装。
示例2:类
Text
可以使用私有继承以
TextPropertiesInterface
的方式实现
class Text: private TextPropertiesInterface { ... }
,但是它也有类似的缺点。
我是一名优秀的程序员,十分优秀!