Pergunta

Eu tenho duas classes: Conta e Operador. Conta contém uma lista de operadores. Agora, sempre que um operador (na lista) recebe uma mensagem que quero notificar objeto Conta para executar alguma lógica de negócios também.

Eu penso em três alternativas sobre como conseguir isso:

1) manter uma referência dentro do operador para o recipiente [conta] objectos e métodos de chamadas directamente. Não absolutamente bom por causa das referências circulares.

2) Usar eventos. Tanto quanto eu sei que não é built-in evento mecanismo de tratamento em Python. Então, isso é um pouco complicado para implementar.

3) Não envie mensagens para operadores directamente. Em vez disso, operam apenas contas e, dentro deles, operadores internamente, manipulador. Este é um pouco limitante, pois, neste caso, não pode passar em torno de referências aos operadores.

Gostaria de saber qual abordagem é a mais vantajosa do ponto de vista arquitectónico. Como você costuma lidar com essa tarefa?

Seria ótimo se você pudesse apontar trechos em Python.

Foi útil?

Solução

Você está sobre-pensar isso. Seriamente. Pitão não é C ++; suas preocupações não são problemas em Python. Basta escrever o que faz sentido em seu domínio do problema.

"Não absolutamente bom por causa das referências circulares."

Por que não? Circularidade não é relevante aqui. relações bidirecionais são grandes coisas. Usa-os. Python coleta de lixo-los muito bem sem qualquer pensamento de sua parte.

O possível problema que você tem com as relações mútuas (birectional)?

" ... operar apenas contas e, dentro deles, internamente, operadores de manipulador. Este é um pouco limitante, pois, neste caso, não pode passar em torno de referências aos operadores. "

O quê? Seus operadores são objetos Python, passar tudo o que quiser. Todos os objetos Python são (em vigor) referências, não se preocupe.

O possível problema que você tem com a manipulação de objetos operador?

Outras dicas

Não existe um "one-size-fits-all" solução para o padrão Observer. Mas, geralmente, é melhor para definir um objeto EventManager onde os interessados ??podem se registrar para determinados eventos e postar esses eventos sempre que eles acontecem. Ele simplesmente cria menos dependências.

Note que você precisa usar uma instância EventManager global, que pode ser problemático durante o teste ou a partir de um ponto de vista geral OO (é uma variável global). Eu recomendo fortemente contra passando a EventManager o tempo todo, porque isso vai encher o seu código.

Em meu próprio código, a "chave" para o registro de eventos é a classe do evento. O EventManager usa um dicionário (classe de evento -> lista de observadores) para saber qual evento vai para onde. No código de notificação, você pode então usar dict.get(event.__class__, ()) para encontrar seus ouvintes.

Gostaria de usar o tratamento de eventos para este. Você não tem que implementá-lo - Eu uso pydispatcher exatamente para este tipo de manipulação de eventos, e é sempre funcionou muito bem (ele usa referências fracas internamente, para evitar o problema de referência circular).

Além disso, se você estiver usando um quadro gui, você já pode ter uma estrutura de eventos que você pode ligar para, por exemplo, PyQt tem sinais e slots.

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

Uma coisa que você não pode saber sobre métodos de instância é que eles são obrigados, quando olhou para cima quando usando a sintaxe de ponto. Em outras palavras dizendo A.notify se liga automaticamente o auto parâmetro de notificar A. Em seguida, pode conter uma referência a esta função sem criar lixo incobráveis.

Por fim, você sempre pode usar Kamaelia para este tipo de coisa.

Existem Observador padrão trechos em toda a web. Uma boa fonte de código confiável é estado ativo, por exemplo:

http://code.activestate.com/recipes/131499/

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top