Question

(Laissant de côté la question de savoir si vous les avez du tout.)

J'ai toujours préféré utiliser la surcharge de fonctions pour vous attribuer le même nom pour le getter et les setters.

int rate() { return _rate; }      
void rate(int value) { _rate = value; }

// instead of     
int getRate() { return _rate; }      
void setRate(int value) { _rate = value; }

// mainly because it allows me to write the much cleaner     
total( period() * rate() );    
// instead of      
setTotal( getPeriod() * getRate() );

Naturellement, j'ai raison, mais je me demandais si les rédacteurs de la bibliothèque avaient une bonne raison?

Était-ce utile?

La solution

Je préférerais les versions get / set car elles indiquent plus clairement ce qui se passe. Si j'ai vu rate () et rate (10), comment puis-je savoir que le taux (10) n'utilise pas simplement 10 dans le calcul pour renvoyer le taux? Je ne le fais pas, alors maintenant je dois commencer à chercher pour comprendre ce qui se passe. Un seul nom de fonction doit faire une chose, pas deux choses opposées.

En outre, comme d'autres l'ont fait remarquer, certains préfèrent omettre le 'get' et laisser le 'set', c'est-à-dire

int Rate( );
void SetRate( int value );

Cette convention est également très claire, je n’aurais aucun problème à lire cela.

Autres conseils

J'ai toujours préféré omettre le "get" dans mes accesseurs, comme vous le faites, avec rate () au lieu de getRate () . Mais surcharger le setter ne me semble pas une très bonne idée, car le nom rate ne signifie pas que l’objet est en cours de mutation. Considérez:

total(period() * rate()); // awesome, very clear

rate(20); // Looks like it computes a rate, using '20'...but for what?  And why ignore the return value?

Que diriez-vous de int rate (); et void setRate (int value); ? Cela a le mérite de ne pas avoir deux fonctions du même nom qui font des choses différentes, et permet toujours period () * rate () .

Il y a quelques années, j'aurais complètement accepté. Plus récemment, un doute a commencé à faire son chemin, car cela rend ambiguë l'adresse d'un getter ou d'un setter. Avec des outils comme tr1 :: bind, c'est vraiment ennuyeux.

Par exemple:

struct A
{
   void Foo(int);
   int Foo()const;
};

std::vector<A> v = ....;
std::vector<int> foos;
// Extract Foo
std::transform(
   v.begin(), v.end(), 
   std::back_inserter(foos), 
   //Ambiguous
   // std::tr1::bind(&A::Foo)
   //must write this instead. Yuck!
   std::tr1::bind(static_cast<int(Foo::*)()>(&A::Foo));
);

Laissant de côté la question de savoir si vous les avez du tout; -)

Je vais y aller et mentionner que cela devrait être une question wiki de la communauté.

Quand j'ai commencé à apprendre le C ++, je cherchais des guides de style, et ceux de Google étaient bons pour certains points:

  • Méthodes en majuscule (c'est juste plus joli).
  • Getters clairement et lowecase ( taux ).
  • les setters explicitement et en minuscule ( setRate ).

Être concis est important, mais pas au prix d’être incomplet ou trompeur. Pour cette raison, je préfère GetFoo () et SetFoo () à Foo () et Foo (int foo).

Il existe plusieurs niveaux pour " Obtenir " et "Paramétrage"

  • J'utilise les options Get et Set pour "rapide". opérations.
  • Si quelque chose prend plus de temps à s'exécuter, il s'agira souvent d'un calcul, car ces noms impliquent que du travail soit nécessaire pour récupérer le résultat.
  • Pour des opérations plus longues, vous commencez à entrer dans des préfixes tels que Charger / Enregistrer, Interroger / Enregistrer, Lire / écrire, Rechercher / Trouver, etc.

Donc, Get / Set peut être attribué à une signification utile et faire partie d’une stratégie de nommage plus large et cohérente.

Bien que le commentaire de Ed soit vrai, je préfère les propriétés réelles à l’antipattre setter / getter. Lorsque 1/3 des méthodes de votre graphique de domaine sont des méthodes factices générées par eclipse, il y a quelque chose qui ne va pas.

Sans propriétés de première classe, toutefois, je pense que l'antipattern est le plus logique.

De plus, cela facilite la complétion de code.

obj.set (espace de contrôle) pour les setters
obj.get (espace de contrôle) pour les getters

Personnellement, je pense que les getters et les setters trouvés par paires sont une odeur de code reportée de "visual". langues et leurs "propriétés". Dans un "bon" classe, les membres de données sont en écriture seule ou en lecture seule mais pas en lecture / écriture.

Je pense que la cause la plus commune des getters et des setters n’est pas assez profonde dans le modèle objet. Dans votre exemple, pourquoi total a-t-il dépassé la période et le taux? Ne sont-ils pas membres de la classe? Donc, vous ne devriez définir que la période et le taux et vous devriez seulement obtenir un total.

Il y a probablement des exceptions, mais je déteste regarder une classe et trouver "getX / setX, getY / setY, etc.". Il semble simplement qu'il n'y ait pas assez de réflexion sur la façon dont la classe DEVRAIT être utilisée et que l'auteur a plutôt facilité la tâche de la classe pour obtenir les données afin de ne pas avoir à se demander comment la classe devrait être utilisée.

Naturellement, j'ai raison.

Un autre problème que personne n’a mentionné est le cas de la surcharge de fonctions. Prenez cet exemple (artificiel et incomplet):

class Employee {
    virtual int salary() { return salary_; }
    virtual void salary(int newSalary) { salary_ = newSalary; }
};

class Contractor : public Employee {
    virtual void salary(int newSalary) {
        validateSalaryCap(newSalary);
        Employee::salary(newSalary);
    }
    using Employee::salary; // Most developers will forget this
};

Sans cette clause utilisant , les utilisateurs de Contractant ne peuvent pas interroger le salaire en raison de la surcharge. J'ai récemment ajouté -Woverloaded-virtual à l'ensemble des avertissements d'un projet sur lequel je travaille, et voilà, cela s'est affiché partout.

J'applique la convention selon laquelle une méthode doit toujours être un verbe et une classe doit toujours être un nom (sauf pour les foncteurs, pour des raisons évidentes). Dans ce cas, un préfixe get / set doit être utilisé pour la cohérence. Cela dit, je suis également entièrement d'accord avec Ed Swangren. Cela me résume à utiliser ces préfixes comme une évidence.

Je préfère éviter les étiquettes get et set, ces informations ne sont pas nécessaires pour permettre au compilateur de faire son travail pour la plupart de ces propriétés simples.

vous pouvez avoir des problèmes:

class Stuff {
  void widget( int something ); // 'special' setter
  const Widget& widget( int somethingelse ) const; // getter
}
Stuff a; 
a.widget(1); // compiler won't know which widget you mean, not enough info

Si votre getter est simplement rate () , votre compilateur se plaint de la redéfinition de votre autre symbole rate , à condition que vous ayez attribué à votre champ un nom significatif, tel que cette. Dans ce cas, vous devez faire quelque chose de stupide comme nommer votre membre _rate ou une autre approche similaire. Personnellement, je déteste voir / taper ces traits de soulignement, donc j'ai tendance à aller avec l'approche getRate () .

C’est évidemment subjectif et c’est justement ma préférence personnelle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top