2009-11-19 6 views
2

Imaginez que vous ayez une classe avec des douzaines de variables membres privées. Chaque variable membre a un getter public et une fonction setter:Classe composée d'autres classes, plus grandes, problème

class Foo 
{ 
public: 
    int GetA() const { return m_a; } 
     : 
    int GetZ() const { return m_z; } 

    void SetA(int val) { m_a = val; } 
     : 
    void SetZ(int val) { m_z = val; } 

private: 
    int m_a; 
     : 
    int m_z 
}; 

Maintenant, nous avons une deuxième classe, qui est composé de Foo (entre autres):

class Bar 
{ 
private: 
    // some instances of other classes of about the same complexity as Foo 
    Foo m_foo; 
}; 

Bar Donc, est essentiellement une classe qui lie les instances d'autres classes dans une même entité.

Les fonctions qui sont passées à une instance de Bar voudront accéder à m_foo afin qu'elles puissent appeler ses fonctions getter et setter. Conscient du conseil de Scott Meyers dans Effective C++ (3ème édition - item # 28), je suis réticent à ajouter quelque chose qui retourne un 'handle' à m_foo, par ex.

Foo& GetFoo() const { return m_foo; } // dubious const, I know 

Ai-je d'autres options que de répliquer chaque getter et setter dans Bar?

Je travaille avec du code hérité qui est assez paresseux pour rendre 'm_foo' public! Mais cela va à l'encontre d'un autre conseil de Scott (item # 22 dans ce cas - "déclarer les membres de données privés").

Un moyen de sortir de cette liaison?

+0

Non seulement le const est douteux, mais c'est faux. m_foo sera const dans le contexte de cette méthode. –

Répondre

2

Vous devez rendre le membre de données public.

Il est déjà conceptuellement public, de toute façon, si vous donnez des getters et setters Bar comme vous le décrivez. Ceci s'applique de manière similaire à toute paire getter/setter dans laquelle le getter renvoie une référence. (Sauf que vous pouvez inclure des hooks pré/post, mais c'est un problème distinct de l'encapsulation.)

+2

Yeesh, les gens ici sont déclencheurs heureux avec le vote vers le bas. Il n'y a rien de mal à rendre les membres publics, tant que vous êtes au courant de ce que vous faites quand vous le faites. Ce n'est pas si difficile de revenir en arrière et de les encapsuler si cela s'avère nécessaire. –

+0

Je continuerais à argumenter pour l'approche getter 'const Foo & GetFoo() const;' et 'Foo & GetFoo();', de cette façon vous pouvez instrumenter les méthodes (avec des logs par exemple) pour traquer un bogue, et c'est plus facile définir des points d'arrêt aussi ... mais conceptuellement, ce serait la même chose. –

+0

@Matthieu M Je suis d'accord avec vous pour dire que c'est la meilleure méthode globale, mais je ne pense pas que la suggestion des membres du public soit si mauvaise qu'elle mérite un vote négatif. Le vote à la baisse devrait être réservé pour les choses qui sont tout à fait fausses, pas seulement avec lesquelles vous n'êtes pas d'accord - aussi virulente soit-elle. Il n'y a rien de mal avec les membres du public, ils sont parfaitement légitimes. Ils nécessitent juste une certaine prévoyance et pourraient conduire à un peu de travail supplémentaire à l'avenir si certaines circonstances surviennent. –

0

Si vous avez de toute façon des classes aussi grandes avec des getters et des setters, je ne pense pas que ce soit un problème de retourner la référence à cet objet , après tout, il y a encore une couche intermédiaire - vous avez toujours le contrôle sur ce qui est défini/obtenu dans Foo. OTOH peut-être que si vous concevez votre classe pour avoir beaucoup de propriétés publiques, vous devriez peut-être reconsidérer votre conception, plus les choses dans la classe seront lourdes.

EDIT: peut-être pourriez-vous changer la structure de données de vos membres publics et les placer dans une carte de quelque sorte? De cette façon, cela permettrait au moins d'économiser de l'écriture. :-)

get("propertyname") 
set("propertyname",value) 
0

Imaginez que vous avez une classe avec des dizaines de variables membres privées. Chaque variable membre a un getter public et une fonction setter.

Euh, je préfère ne pas. Lisez here pourquoi c'est une mauvaise idée.

+0

Hmmm ... article intéressant mais, non merci. Pour plusieurs raisons: maintenance, débogage (beaucoup plus facile de définir le point d'arrêt dans le code que de créer un point d'arrêt conditionnel) et optimisation de la structure des données. – BostonLogan

+0

@BostonLogan: Je ne suis pas sûr de comprendre. L'article soutient qu'une classe pleine de getters/setters n'est pas une classe, c'est simplement une assemblée glorifiée de getters/setters. Tout tourne autour des niveaux d'abstraction et de ce qu'est réellement OO. Cela n'a rien à voir avec le débogage, et en ce qui concerne la maintenance, cela a peu ou pas d'avantage sur la programmation structurée. – sbi

+0

Sbi, je voudrais augmenter la définition de l'auteur de quasi-classes avec "Has no Behavior defined", c'est-à-dire rien de plus qu'une simple structure de données pourrait faire - alors oui, il doit avoir des tripes publiques. Mais si l'objet de la classe peut présenter un comportement et que ce comportement dépend de l'état, alors l'état doit être privé et modifiable seulement par setter. – BostonLogan

0

Pas vraiment, non. Vous pouvez créer un getter et un setter pour chaque getter ou setter dans foo. Vous pouvez rendre les instances foo publiques ou vous pouvez créer un getter et un setter pour foo.

En général, j'ai trouvé que lorsque je fais face à ce genre de situation, il vaut mieux revoir mes raisons pour encapsuler les données dans foo et bar comme je l'ai fait.Souvent, je trouverai qu'il est possible de diviser foo en plusieurs classes et ensuite déplacer les fonctions qui ont besoin d'accéder à chaque partie des données de foo dans la classe appropriée en tant que méthodes. Cela conduit à des variables qui sont en fait des variables membres privées de leurs classes et élimine le besoin de setters et getters. C'est ainsi que la programmation orientée objet est supposée fonctionner. Pour un bon guide sur la façon de faire ce code à l'ancienne, jetez un oeil à de Martin Fowler refactoring.

Questions connexes