2009-04-29 5 views
4

J'ai deux classes: Compte et Opérateur. Le compte contient une liste d'opérateurs. Maintenant, chaque fois qu'un opérateur (dans la liste) reçoit un message, je souhaite également notifier l'objet Compte pour qu'il exécute également une logique métier.Notifier objet conteneur: bonnes pratiques

Je pense que trois alternatives sur la façon d'y parvenir:

1) Organiser une référence dans l'opérateur au conteneur [compte] objet et appeler des méthodes directement. Pas absolument bon à cause des références circulaires.

2) Utiliser les événements. Pour autant que je sache, il n'y a pas de mécanisme de gestion d'événements intégré dans Python. Donc, celui-ci est un peu difficile à mettre en œuvre.

3) N'envoyez pas de messages directement aux opérateurs. Au lieu de cela, opérez seulement les comptes, et en leur sein, en interne, les opérateurs de gestionnaire. Celui-ci est un peu limitant car dans ce cas je ne peux pas passer de références aux opérateurs.

Je me demande quelle approche est la plus avantageuse du point de vue architectural. Comment gérez-vous habituellement cette tâche?

Ce serait bien si vous pouviez signaler des extraits en Python.

Répondre

5

Vous êtes trop penser à cela. Sérieusement. Python n'est pas C++; vos préoccupations ne sont pas des problèmes en Python. Il suffit d'écrire ce qui a du sens dans votre domaine de problème.

"Pas vraiment bon à cause des références circulaires."

Pourquoi pas? La circularité n'a aucune importance ici. Les relations bidirectionnelles sont de grandes choses. Utilise les. Poubelle Python les ramasse très bien sans aucune réflexion de votre part.

Quel problème avez-vous avec les relations mutuelles (bidirectionnelles)?

"... ne gère que les comptes, et au sein de ceux-ci, en interne, les opérateurs de gestionnaire, qui est un peu restrictif car dans ce cas je ne peux pas passer des références aux opérateurs. "

Quoi? Vos opérateurs sont des objets Python, passez tout ce que vous voulez. Tous les objets Python références sont (en effet), ne transpirent pas.

Quel est le problème possible avez-vous avec la manipulation d'objets opérateur?

+0

+1 - Tant que vous utilisez Python 2.5 et ne définissez pas les méthodes __del__, les références circulaires ne sont pas très importantes traiter plus. –

+1

@Jason Baker: J'ai beaucoup utilisé Python pendant 7 ans, je n'ai jamais défini de méthode __del__. Vous n'avez jamais eu de problème avec les relations bidirectionnelles, utilisez-les régulièrement. Ils ont bien fonctionné jusqu'à 2.2. –

+0

Ok, je ne savais pas qu'il traque toutes les références circulaires. Mais que faire si je définis la méthode __del__ (pour une raison quelconque)? Je dois encore les suivre manuellement, non? –

3

Il n'y a pas de solution "taille unique" pour le modèle Observer. Mais généralement, il est préférable de définir un objet EventManager dans lequel les parties intéressées peuvent s'enregistrer pour certains événements et publier ces événements dès qu'ils se produisent. Cela crée simplement moins de dépendances.

Notez que vous devez utiliser une instance globale EventManager, ce qui peut être problématique lors des tests ou d'un point de vue OO général (c'est une variable globale). Je déconseille vivement de passer le EventManager tout le temps car cela encombrera votre code.

Dans mon propre code, la "clé" d'enregistrement des événements est la classe de l'événement. Le gestionnaire d'événements utilise un dictionnaire (classe d'événements -> liste d'observateurs) pour savoir quel événement va où. Dans le code de notification, vous pouvez ensuite utiliser dict.get(event.__class__,()) pour rechercher vos écouteurs.

+0

Merci pour rappeler le nom du modèle. –

3

Je voudrais utiliser la gestion des événements pour cela. Vous n'avez pas besoin de l'implémenter vous-même - j'utilise pydispatcher pour exactement ce type de gestion d'événements, et cela fonctionne toujours très bien (il utilise des références faibles en interne, pour éviter le problème de référence circulaire). De plus, si vous utilisez un framework gui, vous avez peut-être déjà un framework d'événement auquel vous pouvez vous connecter, par exemple PyQt a des signaux et des slots.

+0

+1 pour pydispatcher et ses proches. Il est simple à utiliser et a été conçu pour résoudre exactement la situation que vous avez décrite. Il déconnecte les objets de manière à ce que vous puissiez également connecter des opérateurs à l'intérieur d'autres conteneurs, si vous en avez besoin. –

3
>>> class Account(object): 
...  def notify(self): 
...   print "Account notified" 
... 
>>> class Operator(object): 
...  def __init__(self, notifier): 
...   self.notifier = notifier 
... 
>>> A = Account() 
>>> O = Operator(A.notify) 
>>> O.notifier() 
Account notified 
>>> import gc 
>>> gc.garbage 
[] 
>>> del A 
>>> del O 
>>> gc.garbage 
[] 

Une chose que vous savez peut-être pas les méthodes d'instance est qu'ils liés quand on les regarde lorsque vous utilisez la syntaxe de points. en d'autres termes, en disant A.notify se fixe automatiquement le paramètre auto de notifier à A. vous pouvez ensuite tenir une référence à cette fonction sans créer de poubelle irrécupérable

Enfin, vous pouvez toujours utiliser Kamaelia pour ce type de chose.

+0

Wow, merci pour l'extrait de code et une explication très claire. Approche très intéressante. –

Questions connexes