30 votes

Utiliser getter / setter vs "tell, don't ask"?

Dire, ne pas poser de principe ici est souvent collé à moi lorsque j'utilise les méthodes de lecture ou d'organismes de réglementation, et les gens me disent de ne pas les utiliser. Le site explique clairement ce que je dois et ce que je ne devrais pas faire, mais il n'a pas vraiment expliquer POURQUOI je devrais dire, au lieu de demander. - Je trouver de l'aide getters et setters beaucoup plus efficace, et je peux faire plus avec eux.


Imaginez une classe Warrior avec des attributs health et armor:

class Warrior {
    unsigned int m_health;
    unsigned int m_armor;
};

Maintenant, quelqu'un attaque mon guerrier avec une attaque spéciale qui réduit son armure pendant 5 secondes. À l'aide de setter, il serait comme ceci:

void Attacker::attack(Warrior *target)
{
    target->setHealth(target->getHealth() - m_damage);
    target->setArmor(target->getArmor() - 20);
    // wait 5 seconds
    target->setArmor(target->getArmor() + 20);
}

Et à dire, de ne pas poser de principe, il devrait ressembler à ceci (corrigez-moi si je me trompe):

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

Maintenant, la deuxième on a clairement l'air mieux, mais je ne peux pas trouver les véritables avantages de cette. Vous avez encore besoin de la même quantité de méthodes (increase/decrease vs set/get) et vous perdez l'avantage de vous demander si vous avez besoin de demander. Par exemple, comment vous définissez les guerriers de la santé à 100? Comment pouvez-vous comprendre si vous devez utiliser heal ou hurt, et combien santé, vous avez besoin de guérir ou blesser?

Aussi, je vois les setters et getters utilisé par certains des meilleurs programmeurs dans le monde. La plupart des Api de l'utiliser, et il est utilisé dans la prévention des mst lib tout le temps:

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

Et si je dois décider de croire que des personnes ici reliant moi un article révélateur, ne se posant pas, ou de croire que 90% des grandes entreprises (apple, microsoft, android, la plupart des jeux, etc. etc.) qui ont réussi à faire beaucoup d'argent et de programmes de travail, c'est un peu dur pour moi de comprendre pourquoi serait - dire, ne demandez pas à être un bon principe.

Pourquoi devrais-je l'utiliser (devrais-je?) quand tout semble plus facile avec les getters et les setters?

32voto

Vous avez encore besoin de la même quantité de méthodes (augmentation/diminution vs set/get) et vous perdez l'avantage de vous demander si vous avez besoin de demander.

Vous vous êtes trompé. L'idée est de remplacer l' getVariable et setVariable avec un sens de l'opération: inflictDamage, par exemple. Remplacement d' getVariable avec increaseVariable vous donne différents noms plus obscurs pour les getter et setter.

D'où vient cette question. Par exemple, vous n'avez pas besoin de fournir un setter/getter pour suivre l'armure et de santé différemment, un seul inflictDamage peuvent être traitées par la classe en essayant de bloquer (et d'endommager le bouclier dans le processus) et ensuite de prendre des dommages sur le personnage si le bouclier n'est pas suffisante ou de votre algorithme exige. Dans le même temps, vous pouvez ajouter une logique plus complexe en un seul endroit.

Ajouter un bouclier magique qui permettra d'augmenter temporairement les dégâts causés par vos armes pour un court laps de temps lors de la prise de dommages, par exemple. Si vous avez des accesseurs/mutateurs tous les attaquants ont besoin de voir si vous avez un tel objet, puis appliquer la même logique à plusieurs endroits pour espérer obtenir le même résultat. En la dire à l'approche des attaquants toujours juste besoin de comprendre comment beaucoup de dégâts qu'ils font, et dire à votre personnage. Le personnage peut alors comprendre comment les dégâts sont répartis à travers les éléments, et si elle affecte le caractère de toute autre manière.

Compliquer le jeu et ajouter des armes à feu, alors vous pouvez avoir inflictFireDamage (ou de passer les dommages de l'incendie comme un autre argument à l' inflictDamage de la fonction). L' Warrior peut déterminer si elle est affectée par une résistance au feu de sort et d'ignorer les dégâts de feu, plutôt que d'avoir tous les autres objets du programme d'essayer de comprendre comment leur action va affecter les autres.

2voto

milleniumbug Points 4445

Eh bien, si c'est le cas, pourquoi s'embêter avec des getters et setters après tout? Vous pouvez juste avoir des champs publics.

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

La raison en est simple ici. L'Encapsulation. Si vous avez des setters et getters, c'est pas mieux que le champ public. Vous ne créez pas un struct ici. Vous créez un bon membre de votre programme avec une sémantique définie.

Citant l'article:

Le plus grand danger ici est que, en demandant les données à partir d'un objet, vous ne sont que l'obtention de données. Vous n'obtenez pas un objet, pas dans la grande sens. Même si la chose que vous avez reçu à partir d'une requête est un objet structurellement (par exemple, une Chaîne de caractères), il n'est plus un objet de la sémantique. Il n'a plus aucune association avec ses propriétaire de l'objet. Tout simplement parce que vous avez une chaîne dont le contenu était "ROUGE", vous ne pouvez pas demander à la chaîne ce que cela signifie. Est-ce que les propriétaires de nom de famille? La couleur de la voiture? L' état actuel du compte-tours? Un objet connaît ces choses, les données ne fonctionne pas.

L'article ici suggère ici que "dire, ne pas se demander" est mieux ici parce que vous pouvez pas faire des choses qui n'ont pas de sens.

target->setHealth(target->getArmor() - m_damage);

Il n'a pas de sens ici, parce que l'armure n'a rien en rapport avec la santé.

Aussi, vous vous êtes trompé avec std lib ici. Les accesseurs et mutateurs ne sont utilisés que dans std::complex et c'est à cause de la langue manque de fonctionnalité (C++ n'avais pas eu des références à l'époque). C'est le contraire, en fait. C++ standard library encourage l'utilisation d'algorithmes, de dire les choses à faire sur les contenants.

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

1voto

Adam Liss Points 27815

Une raison qui vient à l'esprit est la capacité à décider de l'endroit où vous souhaitez que le contrôle de l'être.

Par exemple, avec votre setter/getter exemple, l'appelant peut changer le Guerrier de la santé de façon arbitraire. Au mieux, votre setter peut appliquer les valeurs maximale et minimale pour assurer la santé reste valable. Mais si vous utilisez la fonction "envoyer" du formulaire, vous pouvez appliquer des règles supplémentaires. Vous risquez de ne pas permettre à plus d'une certaine quantité de dommages ou de guérison à la fois, et ainsi de suite.

À l'aide de ce formulaire vous donne beaucoup plus de contrôle sur le Guerrier de l'interface: vous pouvez définir les opérations qui sont autorisées, et vous pouvez changer leur mise en œuvre sans avoir à réécrire tout le code qui l'appelle.

0voto

Rick Points 90

À mon point de vue, les deux codes faire la même chose. La différence est dans l'expressivité de chacun. La première (setters anad getters) peut être plus expressive que la seconde (dire, ne demandez).

Il est vrai que, lorsque vous demandez, vous allez prendre une décision. Mais il ne se passe dans la majeure partie du temps. Parfois, vous voulez juste de savoir ou de définir la valeur de l'objet, et ce n'est pas possible avec dire, ne demandez pas.

Bien sûr, lorsque vous créez un programme, il est important de définir les responsabilités d'un objet et assurez-vous que ces responsabilités ne reste plus qu'à l'intérieur de l'objet, de laisser la logique de votre application en dehors de ça. Ce que nous savons déjà, mais si vous avez besoin de demander de prendre une décision qui n'est pas une responsabilité de votre objet, comment voulez-vous faire avec de le dire, ne pas lui demander?

En fait, les accesseurs et mutateurs l'emporte, mais il est courant de voir l'idée de dire, ne demandez pas avec elle. En d'autres termes, certaines Api a getters et les setters et aussi les moyens de le dire, ne demandez pas à l'idée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X