Quais são as vantagens do padrão delegado sobre o padrão observador?

9

No padrão de delegação , apenas um objeto pode ouvir diretamente os eventos de outro objeto. No padrão observador , qualquer número de objetos pode ouvir os eventos de um objeto específico. Ao projetar uma classe que precisa notificar outros objetos de eventos, por que você usaria o padrão delegado sobre o padrão observador? Eu vejo o padrão de observador como mais flexível. Você pode ter apenas um observador agora, mas um design futuro pode exigir vários observadores.

JoJo
fonte
4
O que você quer dizer com "padrão de delegado"? Se você está falando sobre algo como os delegados do .net, pode ter quantos assinantes quiser.
CodesInChaos
Relacionado, embora mais focado em cacau: NSNotificationCenter vs delegação (usando protocolos)?
Mouviciel

Respostas:

7

Não há padrão de delegado em si. Eu vou assumir que você quer dizer Padrão de Delegação .

Pelo que entendi, eles são o inverso completo um do outro e usados ​​para diferentes propósitos.

Geralmente, com um Padrão de observador , qualquer número de objetos de observador escutará um evento em um segundo objeto e atuará no evento. O segundo objeto não tem conhecimento de seus ouvintes. Apenas chama por eles.

Um objeto delegado é passado para o segundo objeto que chama métodos diretamente no delegado. E aí está a vantagem que você está procurando. Em vez de enviar uma única mensagem para vários ouvintes, ele tem controle total sobre um único objeto (em um determinado momento). Veja também Inversão de controle .

pdr
fonte
6

Você está olhando as coisas incorretamente. Um observador vê que um evento específico ocorre. Não afeta, nem possui. Um delegado lida com um evento específico e possui a propriedade do manipulador, mesmo se o delegador possuir a interface para o evento.

Telastyn
fonte
11
Um delegado nada mais é do que um observador de um evento. Um delegado não precisa "manipular" nada. Ele não pode fazer nada com segurança e não afeta (ou pelo menos não deve) a instância que acionou o evento.
Marjan Venema
5
@MarjanVenema - se o objeto A não estiver delegando a responsabilidade do evento ao objeto B, você não está usando o padrão de delegação: está usando o padrão de observador com apenas um observador.
Telastyn
Sim, era nisso que eu estava pensando. Entendi que delegado é o tipo de assinatura de evento a ser usado pelo assinante de um evento "OnWhatever". Aparentemente, delegados em C # não são assinantes únicos, como no Delphi.
Marjan Venema
@Marjan Venema "Um delegado realmente não passa de um observador de um evento." - depende de qual idioma você está falando. No Objetivo C, alguns delegados são responsáveis ​​por fornecer dados - por exemplo, delegados de dados - e um objeto em falta de um delegado de dados não tem dados para apresentar. Nesses casos, há delegações acontecendo, distintas do ato de apenas observar algo.
Occulus
11
@ occulus: obrigado pelo esclarecimento. Pena que as línguas não concordem com a terminologia ... Falar sobre programação de uma maneira independente da linguagem fica um pouco difícil quando as pessoas entendem coisas diferentes pelas mesmas palavras.
Marjan Venema
4

Essa é uma questão de várias compensações.

Trade-offs:

  • flexibilidade (em termos de n> 1 delegados / observadores)
  • custo de envio de uma mensagem
  • resiliência (capacidade de manter a indisponibilidade de delegados / observadores)
  • fácil de usar

Delegar padrão:

  • não muito flexível - não é possível adicionar mais de um delegado (implica alguma forma de "multi-delegado", isto é, padrão de observador)
  • enviar uma mensagem é barato, O (1) - o mesmo custo que chamar qualquer outra função ou método (sem consulta, fila de mensagens ou outra infraestrutura necessária)
  • geralmente não é resiliente - espera-se que os delegados estejam presentes e façam sua parte do trabalho, ou seja, o remetente tende a falhar se não for conhecido
  • fácil de entender, fácil de implementar

Padrão de observador:

  • muito flexível - é esperado adicionar n> 1 observadores por projeto
  • o envio de uma mensagem tem um custo implícito pelo número de observadores, O (n), ou seja, n observadores levam n tempo e mensagens (pelo menos em uma implementação ingênua)
  • geralmente resiliente - geralmente não se espera que os observadores realizem qualquer trabalho por parte do remetente. Ou seja, mesmo que não haja observador, o remetente não é afetado
  • pode se tornar bastante complexo de entender, em particular dos observadores que devem reagir às mensagens (a ordem é importante ?, qual observador responde de que maneira?)
miraculixx
fonte
1

O padrão delegado, como eu o entendo, é conhecido como o mecanismo do manipulador de eventos em outros idiomas, como o Delphi. Como tal, é simplesmente uma implementação do padrão de observador com uma restrição importante: apenas um ouvinte de cada vez.

A desvantagem dos manipuladores ou delegados de eventos é óbvia: apenas um observador.

A vantagem não é tão óbvia: desempenho. Com um padrão de observador, você pode adicionar muitos observadores. Quando ocorre um evento sobre o qual os observadores precisam ser notificados, você precisará enumerar os observadores e enviar uma notificação para cada um. Isso pode atolar rapidamente qualquer instância observada, especialmente quando o número de eventos que exigem notificação também é significativo.

Marjan Venema
fonte
Hã? O delegado C # é apenas a assinatura de um método como um tipo de variável (equivalente a, por exemplo, int (*my_int_f)(int)em C). Eu sempre pensei que eles teriam facilitado a compreensão, fazendo com que funcionasse mais como struct / enum. Um evento é um gancho para uma matriz flexível de ouvintes, usando uma única assinatura de delegado. Você poderia fazer isso sem um evento (e é por isso que eu suponho que o OP significava Padrão de Delegação, que é muito diferente), mas o idioma está facilitando para você.
Pd2
Hmm. Ainda não é tão versado em c #. Eu entendi que os delegados são equivalentes aos tipos de assinatura de eventos, conforme usados ​​pelos eventos "OnWhatever", por exemplo, no Delphi. Então, os eventos C # podem ser assinados por vários ouvintes?
Marjan Venema
A ação genérica <T> é um delegado. Não tem nada a ver com eventos, é uma variável que é repassada. E sim, vários ouvintes podem ouvir um evento.
Pd2
ok obrigado, espero que eu possa mantê-lo reto ... :-) Retirei a referência de C # e foquei mais no mecanismo de eventos.
Marjan Venema
1

Este é um post antigo, mas eu vou gritar de qualquer maneira, porque as outras respostas não lidam com o que está acontecendo ao usar um ou outro padrão, elas parecem ser mais sobre teoria do que prática.

Como funcionam as delegações e os observadores

Com a delegação, o delegador escolhe exatamente quem responderá a um evento específico no momento em que a fonte do evento potencial for criada. Você pode pensar nesse ouvinte como um único observador . No caso do padrão Observador, o observador escolhe quem está observando sempre que lhe apetecer; portanto, as dependências são revertidas quando se trata de observador versus delegação. Com o padrão de observador, pense em um jornal e assinantes como observadores. Os observadores estão no controle de quando o relacionamento é criado. Com a delegação, pense em um funcionário e em um empregador. O empregador está no controle de quando o relacionamento é criado e exatamente quem está encarregado de eventos específicos. Os funcionários não podem escolher em que tarefas estão trabalhando ... geralmente.

Alguns argumentam que a delegação pode ter um observador, mas acho que a diferença real entre os dois é como o tratamento de eventos é atribuído. Você nunca verá um delegado se registrar em um evento. Ele nunca saberá que está lidando com o evento até que ele aconteça e o delegador chame um método público sobre ele.

Vantagem da delegação

Esse padrão é muito rígido e, com a maioria dos projetos elegantes, é mais simples e geralmente mais robusto. Obriga você a declarar seu manipulador de eventos com antecedência no momento da inicialização da origem do evento potencial. Se você precisar de alguém para direcionar o tráfego, atribua um diretor de tráfego antes de abrir a rua. No caso do observador, você deixaria o policial escolher quando direcionar o tráfego a qualquer momento que quisesse.

Desvantagem da delegação

A desvantagem desse design é que ele não é flexível. Se você estivesse implementando algum código para assinar um jornal, o jornal / delegador precisaria identificar exatamente quem pode ler as notícias no segundo em que são criadas. Com o padrão de observador, eles podem ser registrados posteriormente a qualquer momento e o jornal precisará saber apenas que uma nova pessoa se inscreveu.

Quando escolher a delegação?

Quando você precisa de um observador específico, com certeza, e não há motivo para alterar quem está observando, o design rígido do padrão de delegação será benéfico.

Por exemplo, você precisa de uma classe / objeto para lidar com a criação de um pop-up para um erro específico. Não há muitos motivos pelos quais, em tempo de execução, você precisaria mudar quem está lidando com um erro específico; portanto, delegar o erro "Memória insuficiente" a uma única entidade faria sentido. Criar uma matriz de manipuladores em potencial e depois fazer com que esses manipuladores se registrem para o erro "Memória insuficiente" não faria muito sentido; isso seria um exemplo do uso do padrão observador nessa situação. No tempo de execução, você pode alterar os métodos chamados ou o que "delegar" é chamado para eventos variáveis, mas a troca de um manipulador de eventos por um evento específico no tempo de execução não é normal.

Não é impossível trocar delegados como você faria no padrão de observadores, é apenas complicado. No mundo real, talvez você queira trocar policiais de trânsito para que um novo delegador esteja lidando com o tráfego. Pode-se argumentar que um design melhor faria delegar original uma delegacia de polícia e não um único policial, mas eu discordo ...

Usman Mutawakil
fonte