2010-09-14 18 views
0

Ceci est une question de conception générale à partir de la perspective C++. J'ai une classe de conteneur qui contient des objets de 2 autres classes. A partir de la classe conteneur, nous pouvons appeler des méthodes de l'objet de classe contenu "comme nous avons un handle pour l'objet de classe contenu", par exemple. objContainedClass1-> SomeMthod();comment la classe Contained appellera la fonction membre de la classe contenant - Composition en C++

Mais je veux savoir comment l'objet de classe contenu (objContainedClass1) accède aux méthodes de classe conteneur.

Je peux penser à des façons suivantes:

  1. Le conteneur objet de classe passe le pointeur sur lui-même (ce pointeur) au constructeur de la classe contenu. À l'aide de ce pointeur, la classe contenue peut accéder aux méthodes de la classe conteneur.

  2. Rend certaines fonctions de la classe conteneur comme statiques.

D'autres idées pour y parvenir?

Merci

Répondre

6

Ne pas, en général, il est une mauvaise conception pour une classe d'avoir à connaître son contenant. Habituellement, cela signifie que vous avez enfreint le principe de la responsabilité unique.

+2

Je ne vois pas vraiment comment les associations bidirectionnelles ont quelque chose à voir avec le principe de responsabilité unique. Je peux penser à de nombreux cas où les associations bidirectionnelles sont utiles sinon obligatoires. Par exemple, dans les structures arborescentes (voir Composite), il est souvent utile d'avoir une référence au parent dans un nœud. –

+1

Cela dépend plutôt de la situation. Dans un graphique, connaître les autres nœuds n'est pas une grosse affaire. Cependant, dans la plupart des autres cas, c'est une mauvaise idée. Les sockets ne devraient pas connaître le FD_SET dans lequel ils se trouvent, et si votre implémentation le fait, c'est parce que vos sockets font plus d'une chose qui viole la SRP. Ce n'est donc pas automatique non, mais 9 fois sur 10 ce n'est pas la bonne chose à faire. La plupart du temps quand je le vois, le conteneur est un conteneur et fait quelque chose d'autre où il devrait juste contenir un autre pair. – stonemetal

+0

Je voudrais pouvoir supprimer mon downvote, puisque votre commentaire ajoute maintenant la nuance que je pensais manquer dans votre réponse, mais ce n'est plus possible :( –

2

Les deux manières sont OK pour des buts différents. Si tout ce dont vous avez besoin est d'appeler des méthodes statiques, # 2 est OK. Mais si vous avez besoin d'accéder aux méthodes d'instance de la classe conteneur, vous devez avoir un pointeur de classe conteneur, donC# 1 est le chemin.

Dans le cas où vous avez besoin d'une solution générique, mettez en place un modèle d'observateur. Dans ce cas, la classe contenue ne sait rien sur le conteneur, elle soulève juste des événements si nécessaire.

+0

Afin de mettre en œuvre le modèle d'observateur, en particulier lors de la collecte des événements, ne pas objet contenu besoin d'appeler la fonction de classe du conteneur? Soit nous sommes de retour à la question d'origine. –

1

Il existe un certain nombre d'options de mauvaise qualité.

Vous pouvez inclure les classes contenues dans la classe conteneur, si elles ne sont pas utilisées à l'extérieur.

Vous pourriez faire du conteneur un ami des classes contenues (beurk).

Vous pouvez transmettre une référence ou boost :: shared_ptr au conteneur au lieu d'un pointeur brut. La meilleure méthode dépend de la durée de vie de chacun. Évitez les pointeurs bruts si vous le pouvez. Ce que je voudrais essayer de faire est d'isoler l'interface des méthodes conteneur que les objets contenus doivent utiliser (IContainerCallback, par exemple), et l'utiliser comme lien entre les deux. Ainsi, les objets contenus ne référencent le conteneur que de manière indirecte, via une classe d'interface découplée de l'implémentation du conteneur.

0
  • Mettez certaines fonctions de la classe de conteneur en statique.

C'est ce qu'on peut appeler "au revoir OOP!" option et je m'abstiens de l'utiliser autant que possible.

  • l'objet de classe de conteneur passe le pointeur sur lui-même (ce pointeur) pour le constructeur de classe contenue. À l'aide de ce pointeur, la classe contenue peut accéder aux méthodes de la classe conteneur.

A condition que la classe implémente une interface contenant et contenu des cours ne connaissent que l'interface, je ne vois pas de problème. En fait, c'est ce que je fais moi-même. Évidemment, il faut être conscient des pièges de l'approche, quand par exemple. l'objet contenu appelle la méthode du conteneur lors de la destruction de ce dernier (ou tout autre moment où le conteneur est dans un état intermédiaire).

Pour découpler davantage le contenu des classes contenant, des événements ou des messages pourraient également être utilisés. Les objets confinés ne savent pas où ils sont contenus, mais envoient des messages. L'objet contenant lors de la création des objets contenus s'enregistre lui-même en tant que destinataire des messages. Cette technique permet de rendre les objets littéralement indépendants, mais nécessite (1) un cadre de messagerie, (2) en raison de la nature statique de C++ plutôt élaborée à implémenter et (3) nécessite également un niveau de documentation supplémentaire en tant qu'interface de classes.

Sinon, réfléchissez à deux fois pourquoi les objets contenus doivent appeler les méthodes du conteneur. Se pourrait-il que vous ayez besoin de séparer certaines fonctionnalités génériques du conteneur en 3ème classe? Si les objets contenus sont bien les objets actifs et la source logique des événements dans le système, vous aurez peut-être besoin d'un système basique d'événements/messages pour permettre au conteneur d'interroger efficacement les changements d'état des objets contenus.

-1

Ne le faites pas. La responsabilité d'une classe de conteneur est de contenir des choses, rien d'autre. Si vous avez besoin que votre classe de conteneur prenne des actions en fonction de ce qui est contenu dans le conteneur, demandez à un troisième objet d'effectuer ces actions. Par exemple, je suppose que vous réorganisez ou modifiez la collection de classes en fonction du contenu des classes. Au lieu de tenter de le faire dans les classes contenues, effectuez cette action dans une classe qui utilise le conteneur en tant que dépendance.