Na sua forma pura, os padrões são bastante raros e, ao estudar padrões, especialmente nos estágios iniciais, não são tanto os próprios padrões que são importantes que a compreensão dos mecanismos (táticas) com os quais são implementados. Neste artigo, gostaria de descrever um desses mecanismos (gerenciamento de dependências), usado nos padrões Observador e Mediador, mas que geralmente é ignorado. Se você está apenas começando a aprender padrões, bem-vindo ao gato.
Gerenciamento de Dependências
Vamos começar com a instrução: se a classe A depende da classe B, então, sem alterar o comportamento, você pode reescrever o código para que a classe B dependa da classe A ou introduzir outra classe C para que as classes A e B sejam independentes e classe C ligará e dependerá das classes A e B.

Uma classe depende de outra se se referir a seus campos ou métodos. Os campos são facilmente transferidos de uma classe para outra, portanto, vamos nos aprofundar nos métodos com mais detalhes. Suponha que a classe B contenha o método Print, que imprime a data atual no console, e a classe A chama esse método.
class A { private readonly B _b; public A(B b) { _b = b; } public void Run() { _b.Print(); } } class B { public void Print() { Console.WriteLine(DateTime.Now.ToString()); } } public void Test() { var b = new B(); var a = new A(b); a.Run(); }
Portanto, a classe A depende da classe B. Para reverter essa dependência, em vez de chamar o método Print diretamente, geraremos um evento. Agora, a classe A não sabe nada sobre a classe B, e a classe B pode se inscrever em um evento da classe A. classe B dependerá da classe A.
class A { public event EventHandler PrintRequested; public void Run() { PrintRequested.Invoke(this, EventArgs.Empty); } } class B { private readonly A _a; public B(A a) { _a = a; _a.PrintRequested += (s, e) => Print(); } public void Print() { Console.WriteLine(DateTime.Now.ToString()); } } public void Test() { var a = new A(); var b = new B(a); a.Run(); }
O comportamento do código não muda e, no método de chamada, apenas a ordem de inicialização dos objetos e a transferência de dependências para o construtor são alteradas.
De fato, essa é a implementação do padrão
Observer em C #. A classe A é um observável e a classe B é um observador. A classe A é uma classe independente que gera notificações (eventos). Outras classes que estão interessadas nisso podem se inscrever nesses eventos e executar sua lógica. O sistema se torna mais dinâmico devido ao fato de que agora a classe A não precisa conhecer outras implementações. Podemos adicionar novas implementações que se inscreverão em eventos, enquanto a classe A permanecerá inalterada.
Você pode ir além e remover a dependência da classe B em A adicionando código externo que vinculará as duas classes, ou seja, inscreva um objeto nos eventos de outro.
class A { public event EventHandler PrintRequested; public void Run() { PrintRequested.Invoke(this, EventArgs.Empty); } } class B { public void Print() { Console.WriteLine(DateTime.Now.ToString()); } } class C { public void Test() { var a = new A(); var b = new B(); a.PrintRequested += (s, e) => b.Print(); a.Run(); } }
Agora as classes A e B são completamente independentes, cada uma executa sua tarefa e não sabe nada sobre as outras classes. A lógica para a interação entre objetos entra em uma nova classe. Somente a classe C sabe em resposta a quais eventos e sob quais condições os métodos da classe B. devem ser chamados. Assim, a classe C se torna um
mediador .
Resumo: Combatendo a complexidade do sistema
Um dos problemas importantes na programação é a presença de sistemas complexos de classes emaranhadas com um grande número de dependências (sistemas fortemente acoplados). Ao gerenciar dependências, você pode reduzir a conectividade, simplificar o sistema e obter maior agilidade e flexibilidade.
O padrão
Observer reduz a conectividade revertendo dependências. É bem aplicável quando existem várias fontes de eventos e muitos ouvintes que são adicionados dinamicamente. Outro bom exemplo do uso desse padrão é a
programação reativa , quando uma mudança no estado de um objeto leva a uma mudança no estado de todos os objetos dependentes dele, e assim por diante.

O padrão
Mediador reduz a conexão do sistema devido ao fato de que todas as dependências entram em uma classe, o mediador e todas as outras classes se tornam independentes e são responsáveis apenas pela lógica que executam. Assim, a adição de novas classes se torna mais fácil, mas a cada nova classe a lógica do mediador é muito complicada. Com o tempo, se o mediador continuar a crescer incontrolavelmente, torna-se muito difícil de manter.

Uma armadilha perigosa ao usar os padrões Observador e Mediador é a presença de referências circulares, quando eventos da mesma classe, passando por uma cadeia de objetos, levam à geração do mesmo evento novamente. Esse problema é difícil de resolver e complica significativamente o uso de padrões.
Assim, em diferentes circunstâncias, gerenciando dependências, é possível chegar a padrões diferentes, às vezes a uma mistura deles, e às vezes esse mecanismo será útil sem o uso de padrões. Lute contra a complexidade e não produza entidades.
