2010-06-05 10 views
2

Je me demandais si vous pensez que le code suivant indique une mauvaise conception ...Est-ce que ce qui suit indique une mauvaise conception?

class X 
{ 
public: 
    ... 
private: 
    Y y; 
}; 

Class Y 
{ 
public: 
    Y(X& value){ x = value; }; 
private: 
    X& x; 
} 

(à savoir qu'il ya une sorte de dépendance cyclique entre les classes X et Y).

+1

Oui. Oui. –

+0

@Amardeep: Voulez-vous élaborer? –

+1

'x = value' doit être dans une liste d'initialisation, sinon cela ne sera pas compilé. :-) – Thanatos

Répondre

4

Non, je ne pense pas que ce soit un mauvais design. Cela ressemble à une relation parent-enfant (qui est 1-à-1) où l'enfant a un pointeur vers le parent. La raison principale pour une telle conception est si quelqu'un pourrait obtenir une référence à Y sans passer par X. Si tous les accès à Y sont effectués uniquement via X, une telle référence est plus discutable. Comme Billy ONeal le signale, un exemple pourrait être un itérateur qui doit pouvoir référencer la collection à laquelle il appartient. Cela pourrait permettre d'avoir un itérateur dans un tableau qui n'a pas besoin d'être invalidé lorsque le tableau est redimensionné, car il vérifierait l'adresse du tampon courant du tableau et la taille actuelle de chaque accès.

Un autre exemple pourrait être une classe OrderLine (votre X) qui contient une référence à l'élément et compte la quantité, etc. Il dispose également d'un membre de type en option DigitalLicense (votre Y). DigitalLicense contient une grande description cryptée de la licence, donc il est seulement inclus dans ceux OrderLines qui correspond à un produit avec une licence numérique.

Par construction, une référence au DigitalLicense est également placée dans une carte distincte, saisie sur l'ID de licence. Il est maintenant possible de rechercher un DigitalLicense en fonction de l'ID de licence dans la carte. Ensuite, la référence arrière est utilisée pour passer du DigitalLicense au OrderLine. Si le OrderLine a une référence arrière similaire, il est également possible de revenir au Order.

+0

Pouvez-vous élaborer sur quelques-unes des bonnes raisons?Je ne dis pas que vous avez tort, mais je considère toujours un «enfant» qui a besoin d'un pointeur vers son «parent» une «odeur de code», mais je suis toujours prêt à apprendre des exceptions où ce serait un bon design. –

+0

@Charles: Cela peut être utile pour vous permettre de traverser l'arbre dont ils font partie. Je crois que 'std :: map' fonctionne comme ça. Sans ce pointeur parent supplémentaire, l'incrémentation d'un itérateur ne serait pas une opération 'O (1)' comme requis. – jalf

+0

@jalf: Oui, je peux voir que pour des objets intrinsèquement couplés, ça pourrait être une bonne idée. Souvent, cependant, j'ai vu des enfants connaître le type de leur parent (et le fait qu'ils en ont un!) Quand une meilleure conception est de faire ignorer à l'enfant où (ou comment) il est possédé et donc intrinsèquement plus flexible et réutilisable dans plus de situations. Avec des classes appelées «X» et «Y», tout est un peu abstrait. –

7

Cela dépend de ce que vous essayez de faire. Certains modèles, tels que les itérateurs, nécessitent ce type de cycles.

1

Je ne pense pas que ce soit problématique. En fait, c'est un modèle plutôt courant (c'est-à-dire qu'un objet enfant conserve un pointeur/une référence à l'objet parent).

1

Ce n'est pas nécessairement une mauvaise conception, en effet c'est assez commun. Cependant, vous devez être très prudent avec ce type de conception lorsqu'il s'agit de gestion de la mémoire. Vous pouvez vous retrouver avec des bugs difficiles quand chaque classe dépend de l'autre comme ça.

2

auparavant, par ex. dans VB6 c'était une mauvaise conception, car VB ne pouvait pas supprimer les deux objets, où l'un était référencé dans un autre et vice versa. puisque C++ n'a pas de comptage de référence, ce n'est plus un problème.

Questions connexes