使用getter / setter与“告诉,不要问”?

时间:2013-05-19 14:05:59

标签: c++ get set getter-setter

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


想象一下属于Warriorhealth的班级armor

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);
}

并且告诉,不要问原则它会是这样的(如果我错了,请纠正我):

void Attacker::attack(Warrior *target)
{
    target->hurt(m_damage);
    target->reduceArmor(20);
    // wait 5 seconds
    target->increaseArmor(20);
}

现在第二个显然看起来更好,但我找不到这个的真正好处。 您仍然需要相同数量的方法(increase / decrease vs set / get),并且您无法询问是否需要询问。 例如,你如何将战士的健康状况设定为100? 你如何判断是否应该使用healhurt,以及你需要多少健康来治愈或受伤?

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

for (i = 0; i < vector.size(); i++) {
    my_func(i);
}
// vs.
vector.execForElements(my_func);

如果我必须决定是否相信这里的人将一篇关于告诉,不要求的文章或者相信90%的大公司(苹果,微软,安卓,大部分的成功赚了很多钱和工作程序的游戏等等,我很难理解为什么告诉,不要求是一个好的原则。

为什么我应该使用它(我应该?)当getter和setter看起来更容易吗?

4 个答案:

答案 0 :(得分:32)

  

你仍然需要相同数量的方法(增加/减少vs set / get),你就会失去询问是否需要询问的好处。

你弄错了。关键是要用有意义的操作替换getVariablesetVariableinflictDamage。用getVariable替换increaseVariable只会为getter和setter提供不同的更加模糊的名称。

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

例如,添加一个魔法护盾,可以在受到伤害时暂时增加武器造成的伤害。如果你有getter / setter,所有攻击者都需要查看你是否有这样的项目,然后在多个地方应用相同的逻辑,希望得到相同的结果。在 tell 方法中,攻击者仍然需要弄清楚他们做了多少伤害,然后告诉你的角色。然后角色可以弄清楚伤害是如何在物品上传播的,以及它是否会以任何其他方式影响角色。

使游戏复杂并添加火力武器,然后你可以拥有inflictFireDamage(或将火焰伤害作为inflictDamage函数的不同参数传递)。 Warrior可以判断她是否受到火焰抗性法术的影响并忽略火焰伤害,而不是让程序中的所有其他物体试图弄清楚他们的动作将如何影响其他物体。

答案 1 :(得分:2)

那么,如果是这样的话,那么为什么还要为吸气者和制定者烦恼呢?你可以拥有公共领域。

void Attacker::attack(Warrior *target)
{
    target->health -= m_damage;
    target->armor -= 20;
    // wait 5 seconds
    target->armor += 20;
}

原因很简单。封装。如果你有安装者和吸气剂,那就不比公共领域好。您不在此处创建结构。您可以使用定义的语义创建程序的正确成员。

引用文章:

  

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

这里的文章在这里建议“告诉,不要问”在这里更好,因为你不能做那些毫无意义的事情。

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));

答案 2 :(得分:1)

浮现在脑海中的一个原因是能够决定控制的位置。

例如,使用你的setter / getter示例,调用者可以任意改变Warrior的健康状况。充其量,您的setter可能会强制执行最大值和最小值,以确保运行状况仍然有效。但是,如果您使用“tell”表单,则可以强制执行其他规则。您可能不会同时允许超过一定数量的伤害或治疗,依此类推。

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

答案 3 :(得分:0)

在我看来,两个代码都做同样的事情。不同之处在于每个人的表现力。第一个( setters anad getters )可能比第二个更具表现力(告诉,不要问)。

确实,当你问,你将做出决定。但大部分时间都不会发生这种情况。有时您只想知道或设置对象的某些值,而 tell,不要问是不可能的。

当然,在创建程序时,定义对象的响应性非常重要,并确保这些响应性仅保留在对象内部,从而使应用程序的逻辑不在其中。我们已经知道了,但是如果你需要做出一个不是你的对象的责任的决定,你怎么用告诉,不要问

实际上, getters and setters 占优势,但通常会看到告诉,不要与一起讨论的想法。换句话说,一些API有getter和setter以及 tell的方法,不要求想法。