Delegate Design Pattern

O Pattern Delegate é utilizado para separar contextos e, literalmente, delegar responsabilidades.

Conceito

No padrão Delegate, um objeto delga a responsabilidade de executar uma determinada tarefa e as especialidades da implementação não importa para essa classe "delegadora".

O objeto principal possui uma referência ao delegate, usando um protocolo. Dessa forma, o delegate implementa os métodos do protocolo para realizar a tarefa.

Objetivos principais

  1. Desacoplamento: Permite que diferentes classes ou componentes trabalhem juntos sem que conheçam diretamente suas implementações.
  2. Reutilização de código: Componentes podem ser reutilizados com diferentes delegados, fornecendo maior flexibilidade.
  3. Especialização: Permite que diferentes objetos especializados realizem diferentes tarefas sem modificar o objeto principal.

Estrutura básica

  1. Protocolo (interface): Define os métodos que o delegado deve implementar.
  2. Objeto principal: É o objeto que precisava realizar alguma ação, mas delega a tarefa ao delegado.
  3. Objeto delegado: É o objeto que realmente executa a ação em nome do principal.

Pseudocódigo

classDiagram
    class DelegateProtocol {
        <<protocol>>
        +doSomething()
    }

    class Main {
        -delegate: DelegateProtocol
        +mainMethod()
    }

    class Delegate {
        +doSomething()
    }

    Main --> DelegateProtocol : delegate
    Delegate ..|> DelegateProtocol : implements

interface DelegateInterface is
    method doSomething()


class Main
    field delegate: DelegateInterface?
    
    method mainMethod() is
        print("Starting task")
        delegate?.doSomething()


class Delegate implements DelegateInterface
    method doSomething() is
        print("Doing somehting as delegate")


main = Main()
delegate = Delegate()

main.delegate = delegate
main.mainMethod()

Vantagens

  • Separação de responsabilidades: A delegação permite que a lógica de uma tarefa seja separada em outra classe.
  • Modularização: A delegação permite que o código seja quebrado em partes menores e mais gerenciáveis.
  • Facilidade de substituição: O comportamento delegado pode ser facilmente substituído sem alterar o objeto principal.
  • Facilita testes: Ao usar delegates, é possível simular comportamentos para realizar testes sem ter que alterar o código original.
  • Extensibilidade: O delegate permite que uma funcionalidade seja estendida, caso a implementação do protocolo lide de forma diferente com a delegação de responsabilidade.

Referências

Replace Inheritance with Delegation Omar Saibaa, Delegate Design Pattern in iOS

Esse é um dos meus patterns favoritos, trabalho dando manutenção em um framework atualmente e quase sempre que me deparo com uma situação onde preciso estender a funcionalidade ou padronizar alguma biblioteca de terceiros o delegate está lá para ser a solução do problema

Também gosto muito do padrão Delegate! Além dos exemplos que você mencionou, ele é bastante útil em cenários de aplicativos white-label, onde diferentes comportamentos podem ser delegados sem modificar o código principal. Trabalho com desenvolvimento para iOS com Swift, o Delegate é essencial para manter uma arquitetura mais estruturada e organizada.

bom dia, sra.

este pattern corrobora para com o L com o I do solid, certo?

as referências que vc apresentou não apresentam referências bibliográficas tais literaturas com escopo acadêmico. a sra já viu esse pattern na faculdade? estou comentando sobre isso, pois eu queria entender com quais paradigmas esse pattern é mais amigável. talvez o funcional, tal quando orientado a protótipos, como o javascript.

já utilizou esse pattern antes? poderia trazer um exemplo prático?

pode até ser um aprofundamento para outro post.

além disso, como a sra colocou um diagrama no markdown? ficou bacana.

aguardo retorno.

Boa tarde! Sobre SOLID, o padrão Delegate realmente pode estar alinhado ao **L** (Liskov Substitution Principle), já que a classe delegadora deve confiar que o objeto delegate executará a tarefa, sem se preocupar com os detalhes de sua implementação. Isso garante que as substituições são seguras, pois o delegate deve seguir um protocolo definido. Quanto ao **I** (Interface Segregation Principle), o uso de um protocolo específico para delegação permite que as classes implementem apenas as responsabilidades que lhes cabem, sem métodos desnecessários. Estudei esse pattern para aplicar no trabalho, realmente não tenho referências acadêmicas. (sinto muito 😭) O padrão Delegate está bem alinhado com a orientação a objetos e é extremamente intuitivo em linguagens como Swift, onde o uso de protocolos e delegação é parte fundamental da arquitetura. Isso facilita muito o gerenciamento de responsabilidades entre classes de forma limpa e organizada. Já em linguagens como JavaScript, a aplicação do Delegate não é tão intuitiva, porque a linguagem oferece alternativas mais diretas, como callbacks, que são mais naturais no seu ecossistema. Sobre programação funcional, infelizmente vou ficar te devendo uma resposta por agora, não sou muito familiarizada com sua aplicação, então qualquer coisa que eu falar vai ser improviso/suposição. Assim que possível vou estudar sobre e te trazer um posicionamento mais concreto acerca desse tema. De qualquer forma, como em qualquer padrão de projeto, é importante lembrar que cada caso é um caso. Se o Delegate for aplicado fora de um contexto adequado, pode acabar resultando em um código poluído ou até mesmo em overengineering, complicando mais do que resolvendo qualquer problema. É sempre importante avaliar se a aplicação de um pattern realmente traz benefícios para a situação específica. Utilizo esse pattern no trabalho. Vou preparar um exemplo prático e compartilho em breve! Fico feliz que tenha gostado do diagrama; utilizei o [Mermaid](https://mermaid.js.org/intro/) para gerá-lo diretamente no markdown, é uma ferramenta bem prática. Se tiver mais dúvidas ou sugestões, estou à disposição!

Po, interessante, consegue mostrar um exemplo comparativo? Tipo, uma situação "problema" que isso aí consiga resolver / melhorar a performance (se for o objetivo)

Sinceramente, não sei se esse pattern traz algum ganho em performance. O objetivo principal do padrão Delegate não é melhorar performance, mas sim organizar melhor o código e promover o desacoplamento entre classes. Vou preparar um exemplo prático para demonstrar uma situação "problema" onde ele pode ser aplicado para deixar o código mais limpo e modular, e compartilho em breve!

Parabéns, muito legal 👏👏👏👏👏👏