C++ 使用getter/setter vs";告诉我,唐';“不要问”吗;?

C++ 使用getter/setter vs";告诉我,唐';“不要问”吗;?,c++,get,set,getter-setter,C++,Get,Set,Getter Setter,当我使用getter或setter时,告诉,不问原则经常粘贴到我的身上,人们告诉我不要使用它们。 该网站清楚地解释了我应该做什么和不应该做什么,但它并没有真正解释为什么我应该告诉别人,而不是询问。 我发现使用getter和setter更有效,我可以用它们做更多的事情 想象一个拥有属性健康和护甲的职业战士: class Warrior { unsigned int m_health; unsigned int m_armor; }; 现在有人用特殊攻击攻击我的战士,减少他的护甲

当我使用getter或setter时,告诉,不问原则经常粘贴到我的身上,人们告诉我不要使用它们。 该网站清楚地解释了我应该做什么和不应该做什么,但它并没有真正解释为什么我应该告诉别人,而不是询问。 我发现使用getter和setter更有效,我可以用它们做更多的事情


想象一个拥有属性
健康
护甲
的职业
战士

class Warrior {
    unsigned int m_health;
    unsigned int m_armor;
};
现在有人用特殊攻击攻击我的战士,减少他的护甲5秒。使用setter的方法会是这样的:

void Attacker::attack(Warrior *target)
{
    target->setHealth(target->getHealth() - m_damage);
    target->setArmor(target->getArmor() - 20);
    // wait 5 seconds
    target->setArmor(target->getArmor() + 20);
}
使用“告诉,不问”原则,它看起来是这样的(如果我错了,请纠正我):

现在第二个看起来很好,但我找不到它的真正好处。 您仍然需要相同数量的方法(
增加
/
减少
设置
/
获取
)并且您失去了询问是否需要询问的好处。 例如,如何将战士的生命值设置为100? 您如何确定是否应该使用
治疗
伤害
,以及治疗或伤害需要多少健康

此外,我看到世界上一些最好的程序员正在使用setter和getter。 大多数API都使用它,并且它一直在std库中使用:

for (i = 0; i < vector.size(); i++) {
    my_func(i);
}
// vs.
vector.execForElements(my_func);
for(i=0;i
如果我必须决定是否相信这里的人链接我的一篇关于告诉,而不是询问的文章,或者相信90%的大公司(苹果,微软,安卓,大多数游戏,等等),他们已经成功地赚了很多钱和工作程序,我很难理解为什么会告诉我,不要问是不是一个好的原则


当使用getter和setter时,一切看起来都很简单,为什么我要使用它呢?

好吧,如果是这样的话,为什么还要使用getter和setter呢?您可以只使用公共字段

void Attacker::attack(Warrior *target)
{
    target->health -= m_damage;
    target->armor -= 20;
    // wait 5 seconds
    target->armor += 20;
}
原因很简单。封装。如果你有二传手和传接手,这并不比公共场地好。这里不创建结构。您可以使用定义的语义创建程序的适当成员

引述该条:

这里最大的危险是,通过从对象请求数据,您 我们只获取数据。你不会得到一个不在大范围内的物体 感觉即使您从查询中收到的是对象 在结构上(例如字符串),它在语义上不再是对象。 它不再与其所有者对象有任何关联。只是因为 你有一个字符串,它的内容是“红色”,你不能问这个字符串 这意味着什么。它是主人的姓吗?汽车的颜色?这个 转速表的当前状况?一个物体知道这些东西, 数据不存在

这篇文章在这里建议,“说,不要问”在这里更好,因为你不能做没有意义的事情

target->setHealth(target->getArmor() - m_damage);
这在这里没有意义,因为盔甲与健康无关

还有,这里的std lib是错误的。getter和setter仅用于
std::complex
中,这是因为语言缺乏功能(当时C++没有引用)。事实上,恰恰相反。C++标准库鼓励算法的使用,告诉容器上的事情。
std::for_each(begin(v), end(v), my_func);
std::copy(begin(v), end(v), begin(u));

我想到的一个原因是能够决定控制权的位置

例如,在setter/getter示例中,调用方可以任意更改战士的健康状况。充其量,setter可能会强制执行最大值和最小值,以确保运行状况保持有效。但如果你使用“告诉”形式,你可以强制执行其他规则。您可能不允许同时造成超过一定数量的伤害或治疗,以此类推


使用此表单可以更好地控制Warrior的接口:您可以定义允许的操作,并且可以更改它们的实现,而无需重写调用它们的所有代码。

在我看来,这两个代码做的事情是相同的。区别在于每一个的表现力。第一个(二传者和获得者)比第二个(说,不问)更有表现力

诚然,当你问的时候,你会做出决定。但这种情况在大多数情况下都不会发生。有时,您只想知道或设置对象的某些值,而这在告诉时是不可能的,不要问

当然,当您创建一个程序时,定义一个对象的责任并确保这些责任只保留在对象内部是很重要的,让应用程序的逻辑脱离它。这一点我们已经知道了,但是如果你需要要求做出一个不是你的目标的责任的决定,你如何用“告诉,不要问”来做出决定

事实上,能手和二传手占了上风,但这是常见的想法告诉,不要问它一起。换句话说,有些API有getter和setter以及tell、don-ask思想的方法

您仍然需要相同数量的方法(增加/减少与设置/获取),并且您失去了询问是否需要询问的好处

你搞错了。关键是用一个有意义的操作来替换
getVariable
setVariable
:例如,
造成伤害
。将
getVariable
替换为
increaseVariable
只会为getter和setter提供不同的更模糊的名称

这有什么关系。例如,您不需要提供一个setter/getter来以不同的方式跟踪护甲和生命值,类可以通过尝试阻止(并在过程中损坏盾牌)然后在盾牌不足或您的算法要求时对角色造成伤害来处理单个
造成伤害。同时,您可以在单个位置添加更复杂的逻辑

std::for_each(begin(v), end(v), my_func); std::copy(begin(v), end(v), begin(u));