2009-04-29 2 views
4

У меня есть два класса: учетная запись и оператор. Учетная запись содержит список операторов. Теперь, когда оператор (в списке) получает сообщение, я хочу уведомить объект «Учетная запись», чтобы выполнить некоторую бизнес-логику.Уведомление объекта-контейнера: лучшие практики

Я думаю, что из трех альтернатив, о том, как достичь этого:

1) Держите ссылку внутри оператора в контейнере [Account] объекта и прямого вызова методов. Не совсем хорошо из-за круговых ссылок.

2) Использование событий. Насколько я знаю, в Python нет встроенного механизма обработки событий. Таким образом, это немного сложно реализовать.

3) Не отправляйте сообщения операторам напрямую. Вместо этого используйте только учетные записи и внутри них, внутренние, обработчики. Это немного ограничивает, потому что в этом случае я не могу передавать ссылки на операторов.

Интересно, какой подход является наиболее выгодным с архитектурной точки зрения. Как вы обычно справляетесь с этой задачей?

Было бы здорово, если бы вы могли указать фрагменты в Python.

ответ

5

Вы передумали это. Шутки в сторону. Python не C++; ваши проблемы не являются проблемами в Python. Просто напишите, что имеет смысл в вашей проблемной области.

«Не совсем хорошо из-за циркулярных ссылок».

Почему нет? Циркулярность здесь вообще не имеет отношения. Двунаправленные отношения - отличные вещи. Используй их. Мусор Python собирает их просто отлично, не думая с вашей стороны.

Какая у вас проблема с взаимными (двусторонними) отношениями?

«... работать только с учетными записями и внутри них внутренними операторами-обработчиками. Это немного ограничивает, потому что в этом случае я не могу передавать ссылки на операторов. "

Что? Ваши операторы являются объектами Python, проходят все, что вы хотите. Все объекты Python являются (в сущности) ссылки, не переживайте.

Что возможно проблема вы имеете с манипулируя объектами Operator?

+0

+1 - Пока вы используете Python 2.5 и не определяете методы __del__, круговые ссылки просто не являются большими больше. –

+1

@ Джейсон Бейкер: сильно использовал Python в течение 7 лет, никогда не определял метод __del__. Никогда не было проблем с двунаправленными отношениями, используйте их регулярно. Они отлично работали вплоть до 2.2. –

+0

Хорошо, не знал, что он отслеживает все круговые ссылки. Но что, если я определяю метод __del__ (по какой-либо причине)? Я все еще должен отслеживать их вручную, не так ли? –

3

Существует не одноразовое решение для шаблона Observer. Но обычно лучше определить объект EventManager, где заинтересованные стороны могут зарегистрироваться для определенных событий и публиковать эти события всякий раз, когда они происходят. Он просто создает меньше зависимостей.

Обратите внимание, что вам нужно использовать глобальный экземпляр EventManager, который может быть проблематичным во время тестирования или с общей точки зрения OO (это глобальная переменная). Я настоятельно рекомендую не пропускать EventManager все время, потому что это загромождает ваш код.

В моем собственном коде «ключ» для регистрации событий является классом события. EventManager использует словарь (класс события -> список наблюдателей), чтобы узнать, какое событие происходит там. В коде уведомления вы можете использовать dict.get(event.__class__,()), чтобы найти своих слушателей.

+0

Спасибо за напоминание о названии картины. –

3

Я использовал бы обработку событий для этого. Вам не нужно реализовывать его самостоятельно - я использую pydispatcher для такого рода обработки событий, и он всегда работает очень хорошо (он использует слабые ссылки внутри, чтобы избежать проблемы с круговой ссылкой).

Кроме того, если вы используете фреймворк gui, у вас может быть фреймворк событий, к которому вы можете подключиться, например, PyQt имеет сигналы и слоты.

+0

+1 для pydispatcher и его родственников. Он прост в использовании и предназначен для решения именно той ситуации, которую вы описали. Он отделяет объекты таким образом, чтобы вы могли подключать операторы внутри других контейнеров, если вам это нужно –

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 
[] 

Одна вещь, которую вы можете не знать о методах экземпляра в том, что они связаны, когда посмотрел при использовании точечный синтаксис. другими словами говоря A.notify автоматически связывает параметр само по уведомляют A. вы можете провести ссылка на эту функцию без создания бесполезного мусора.

И наконец, вы всегда можете использовать Kamaelia для этого типа вещей.

+0

Вау, спасибо за фрагмент кода и очень четкое объяснение. Очень интересный подход. –

Смежные вопросы