2009-02-19 5 views
2

Imaginer ces relations:2x un à de nombreuses relations dans OO

  • 1 A a beaucoup B
  • 1 B a beaucoup Cassiopéens ...

À l'inverse:

  • C a 1 B
  • B a 1A
  • Par transitivité, C a 1 A

Pour modéliser cette relation dans DB, nous avons:

TableA 
a_id 

TableB 
b_id 
a_id (fk to TableA) 

TableC 
c_id 
b_id (fk to TableB) 

Pour modéliser cette relation OO, nous avons:

objA 
objB 
objC 

Et. .. - objB fait référence à objA - objC fait référence à objB

Si objC a rencontré hod qui a besoin d'appeler une méthode d'objA, que ferez-vous?

Option 1.

b.getA().runMethodX() 

Beaucoup ppl que je connais serait cela, mais je l'ai aussi appris que ce n'est pas bon parce Geta() est pas un comportement de B dans un sens pur OO . Cela revient à faire de la programmation procédurale. D 'accord en désaccord?

Option 2.

Soit objc a une référence directe à objA et objB par injection constructeur/poseur

Est-ce une bonne idée? mais alors objB que objC a aussi référence à objA. Est-ce correct? Ou tant qu'il ne s'agit pas de références d'objets cycliques, est-ce acceptable?

Option 3.

Déplacer la méthode en question objA et passer objc dans le paramètre.

Je ne suis pas sûr si cela considère comme une option. Je pense que ça ne marchera pas dans tous les cas. Avoir la méthode dans objC réduire au strict minimum qui ne fonctionne que sur ses états, et laissez objA faire ce que objA doit faire avant ou après.

Option 4. (Délégation)

ajouter runMethodXinA() à B, il appelle

a.runMethodX() 

C appelle

b.runMethodXinA() 

J'ai essayé cette méthode avant, mais B finirai très probablement par avoir autant de méthodes comme A, et n'a pas 1 méthode dans les deux B et A viole DRY?

Quelles sont vos raisons? D'autres options? Commentaires? Suggestions?

Répondre

2

L'option 2 est une duplication d'informations assez dangereuse, en plus de tout ce qui peut sortir de la forme du graphe de référence en fonction de votre environnement.

L'option 3 pourrait avoir un sens si la méthode dépend en quelque sorte du type d'objA, comme une sorte de double répartition.

L'option 1 va à l'encontre de la loi de Demeter, mais il semble que ce soit l'option la moins intrusive.

Vous pouvez également envisager une méthode de transfert sur objB qui transmet l'appel à objA.

0

de votre liste de choix, le choix est l'option 4, car il obéit à la Law of Demeter

  • option 1 viole la loi de Déméter
  • option 2 présente des références redondantes et constitue une violation de la loi de Déméter indirectement
  • option 3 pollue l'objet A avec la connaissance de l'objet C, ce qui est également contraire sans doute la loi de Demeter (en sens inverse)

qui laisse l'option 4

il peut y avoir une option 5, mais qui est au-delà de la portée de la question initiale ;-)

+0

Veuillez également poster l'option 5. :) – Henry

+0

@ [Henry]: l'option 5 dépend de la connaissance des objets A, B et C, ce que je n'ai pas - Je trouve le "besoin" de l'objet C d'appeler les méthodes de l'objet A hautement suspectes, l'option 5 est probablement "Do not Do That" ;-) –

0

Je pense que la question est quel genre de modèle que vous allez pour. Si vous optez pour un modèle relationnel où vous connaissez toute la structure à l'avance et qui ne changera pas, l'option 1 est acceptable. Autrement dit, les données/méthodes dans A dans un modèle d'organisation particulier est nécessaire pour C.

L'option 2 peut sembler une bonne idée. mais vous enregistrez essentiellement deux références au même objet. Maintenant, si B est mappé à un A différent, B doit notifier C pour changer également sa référence. Pas bien.

Cependant, l'option 4 semble être la bonne façon d'opter pour une véritable approche OO. Le point étant que A peut changer sa structure et il suffit d'adapter B - l'enfant immédiat. C ne sait pas et ne se soucie pas de savoir comment A est implémenté, il suffit que A existe et que B sache quoi faire avec.

+0

Oups, j'aurais dû indiquer getB() en C est vraiment une méthode privée. Il va juste retourner la propriété privée B. – Henry

+0

J'ai mis à jour la question. Changé "getB()" juste "b". – Henry

0

Avez-vous réellement besoin des pointeurs arrière de C à B vers A, ou en avez-vous seulement pour pouvoir accéder à A à partir de C? Peut-être que A devrait prendre la responsabilité de créer B et C et de gérer leur relation. Dans ce scénario, A peut s'insérer dans C lorsqu'il crée C (ex C peut avoir un constructeur qui prend A).

Vous pouvez également isoler la fonction sur A dont C a besoin et créer une interface pour celle-ci. L'interface (au lieu de A) sera transmise à C en construction. Cela découplera C de A.

0

N ° 1 ou N ° 4 selon les circonstances. Dans mon logiciel de coupe de métal, nous avons de nombreux cas où nous devons connaître le parent/l'origine d'un objet. Par exemple, nous avons une collection de chemins sur un raccord et chaque chemin a une propriété Ajustement qui renvoie l'ajustement qui l'a créé.

Toutefois, si un objet connecté est présent simplement parce qu'il aide l'objet original à remplir son rôle (comme le support mathématique), alors la délégation est probablement la meilleure approche.

Si l'objet connecté MODIFIE l'objet d'origine, il est probablement préférable d'utiliser le modèle de visiteur. Le seul inconvénient est que dans la plupart des POO, vous devez faire attention aux objets doublement liés. La récupération de place échoue souvent sur les objets qui ont des liens parent-enfant qui se connectent les uns aux autres. Et c'est une erreur commune d'oublier de nettoyer le lien parent-enfant. Avec les POO qui prennent en charge la création et la consommation d'événements, vous pouvez contourner ce problème. En utilisant des procurations. Le parent remettra à l'enfant un objet proxy au lieu de lui-même. Lorsque l'enfant a besoin du parent, il recevra une référence de l'objet proxy. L'objet proxy déclenche à son tour un événement qui provoque le retour du parent lui-même. Il n'y a pas de liens durs, donc le problème du programmeur ou du garbage collector qui ne nettoie pas est atténué.

Questions connexes