C# - Padrão Comportamental Gof - Mediator
Neste artigo vou apresentar o padrão comportamental Gof Mediator. |
Segundo a
definição da Gang Of Four(GoF), o padrão
Mediator
define um objeto que encapsula como um conjunto de objetos interage.
Este padrão promove o acoplamento fraco evitando que os objetos se refiram
explicitamente uns aos outros e permite que você varie sua interação de forma
independente.
Podemos dizer que o padrão Mediator gerencia as interações de diferentes objetos, e, usando uma classe mediadora, centraliza todas as interações entre os objetos, visando diminuir o acoplamento e a dependência entre eles.
Desta forma, neste padrão, os objetos não conversam diretamente entre eles, e
toda comunicação precisa passar pela classe mediadora. Assim este padrão permite
que um grupo de objetos se comuniquem entre si sem que haja acoplamento entre
eles através de um objeto mediador.
Podemos dizer que a intenção do padrão Mediator é definir um objeto que
encapsula como um conjunto de objetos interagem.
Mediator : Exemplo
Para entender
melhor como Mediator age vamos considerar o seguinte cenário
1- Suponha que temos 4 objetos : A, B , C e D.
E esses 4 objetos precisam se comunicar uns com os outros :
2- Suponha que o
objeto A quer se comunicar com o objeto B.
3- Então o objeto A deve conhecer/ter uma referencia ao Objeto B e, usando essa
referência, o Objeto A pode chamar o método do Objeto B e assim se comunicar com
ele
4- Da mesma forma se o objeto B quiser enviar uma mensagem para o objeto C então
ele deverá conhecer/ter uma referência para o objeto C e usando essa referência
ele irá chamar o método do objeto C e enviar uma mensagem
5- Isso se repete para os demais objetos que desejam interagir
- O objeto C com o objeto D
- O objeto D com o objeto A
- O objeto A com o objeto C
- O objeto B com o objeto D
Este cenário apresenta um forte acoplamento entre os objetos :
Pois temos um monte de objetos que precisam conhecer/ter uma referência entre
si, ou seja, cada objeto precisa ter conhecer os objetos com os quais deseja se
comunicar.
Aqui temos apenas 4 objetos agora imagine um projeto do mundo real podemos ter
centenas/milhares de objetos desejando se comunicar uns com os outros.
Como permitir que um grupo de objetos se comunique entre si sem que haja
acoplamento entre eles ?
Aqui entre em cena o padrão Mediator.
Podemos então resolver esses problemas introduzindo um objeto Mediator, que será
responsável por intermediar a comunicação entre todos os objetos.
Assim agora cada objeto não precisa mais conhecer os demais objetos bastando
apenas conhecer o objeto Mediator e enviar uma mensagem para este objeto.
Aqui o objeto Mediator vai atuar recebendo a mensagem de cada objeto e roteando
a mensagem para o objeto de destino.
É assim que o
padrão Mediator funciona, e , com esse padrão, cada objeto possui uma única
responsabilidade e consegue se comunicar com outros objetos sem a necessidade de
conhece-los, ou seja, cada objeto, trabalha de forma independente e isolada, não
havendo acoplamento entre eles.
Diagrama UML
O diagrama UML do padrão Mediator segundo o Gof apresenta os seguintes participantes :
1- Mediator -
- Define uma
interface para comunicação com os objetos Colleague e os métodos que podem ser
chamados por objetos Colleague;
2- ConcreteMediator -
- Implementa o contrato definido em Mediator e mantêm uma referência aos objetos Colleague e a comunicação e transferência de mensagens entre as classes Colegue;
3- Colleague
- Mantém uma
referência ao seu objeto Mediator e se comunica com o Mediator sempre que
necessário;
3- ConcreteCollegue 1 e 2
- Essas classes se comunicam entre si por meio do Mediator, cada uma herda o campo mediator da classe Colleague;
Quando podemos usar o padrão
Podemos usar o padrão Mediator nos seguintes cenários :
- As mudanças no
estado de um objeto afetam muitos outros objetos;
- O grande número de interconexões entre os objetos torna o sistema pesado e
difícil de mudar;
- Você deseja ser capaz de alterar as partes de um sistema independentemente
umas das outras;
- Quando existem muitos relacionamentos entre os objetos e um ponto comum de
controle ou comunicação é necessário;
Vantagens do padrão
Como vantagens deste padrão temos que :
- Desacoplamento
entre os objetos, pois nenhum objeto se conhece na comunicação;
- O fluxo de comunicação está centralizado, com isso, alterações no mediador não
afetam seus ouvintes;
- Mudanças podem ser aplicadas facilmente nos objetos, pois são independentes;
- Eliminação de relacionamentos muitos para muitos (são todos substituídos por
relacionamentos um para muitos);
Desvantagem
E como desvantagem deste padrão temos que:
- A centralização
pode ser uma fonte de gargalos de desempenho e de risco para o sistema em caso
de falha;
- Na prática os mediadores tendem a se tornarem mais complexos;
Exemplo de implementação do padrão Mediator
Como exemplo de implementação do padrão Mediator vamos considerar o ambiente do Facebook No Facebook podemos criar grupos específicos no qual podemos compartilhar mensagens e recursos.
Vamos supor que temos um grupo no Facebook com alguns membros (para o exemplo eu vou considerar apenas 4 membros) :
Assim cada membro poderá compartilhar mensagens com quaisquer outros membros do
grupo, e, se um usuário quiser compartilhar um link sobre algum assunto ele irá
enviar a mensagem para o mediator que vai repassar a todos os membros do
grupo.
Implementação prática
Levando em conta este cenário vamos implementar o padrão Mediator usando uma aplicação Console .NET Core (.NET 5.0) criada no VS 2019 Community.
A seguir temos o diagrama de classes obtido a partir do VS 2019 na implementação do padrão:
Podemos identificar as seguinte classes :
-
User - Representa o Colleague;
-
ConcreteUser - Implementa a interface
User;
- FacebookGroupMediator -
Representa o Mediator;
- ConcreteFacebookGroupMediador -
Implementa o Mediator;
A seguir temos o código usado na implementação:
1- A interface User
public abstract class User { protected FacebookGroupMediator mediator; protected string name; public User(FacebookGroupMediator mediator, string name) { this.mediator = mediator; this.name = name; } public abstract void Send(string message); public abstract void Receive(string message); } |
2- A classe ConcreteUser
public class ConcreteUser : User { public ConcreteUser(FacebookGroupMediator mediator, string name) : base(mediator, name) {} public override void Receive(string message)
{
Console.WriteLine($"{name} : recebida <= { message}");
}
public override void Send(string message)
{
Console.WriteLine($"{name} : enviada => {message}\n");
mediator.SendMessage(message, this);
}
}
|
3- A interface FacebookGroupMediator
public interface
FacebookGroupMediator { void SendMessage(string msg, User user); void RegisterUser(User user); } |
-
SendMessage - envia a mensagem para todos os
membros do grupo exceto para quem compartilhou a mensagem;
- RegisterUser - registra um usuário em um grupo;
4- Classe ConcreteFacebookGroupMediator
public class
ConcreteFacebookGroupMediator : FacebookGroupMediator { private List<User> usersList = new List<User>(); public void RegisterUser(User user) { usersList.Add(user); } public void SendMessage(string message, User user) { foreach (var u in usersList) { // mensagem não sera recebida por quem a estiver enviando if (u != user) { u.Receive(message); } } } } |
7- Program
|
A execução do projeto irá apresentar o seguinte resultado:
O padrão mediator permite manter o nosso domínio seguro e ajuda a evitar o acoplamento desnecessário. Este padrão vem ganhando espaço com a necessidade de softwares mais robustos demandarem de técnicas como DDD, CQRS e microsserviços.
Padrões relacionados com o padrão Mediator:
Pegue o código do projeto aqui : Mediator1.zip
"E tu, ó
menino, serás chamado profeta do Altíssimo, Porque hás de ir ante a face do
Senhor, a preparar os seus caminhos; Para dar ao seu povo conhecimento da
salvação, Na remissão dos seus pecados;"
Lucas 1:76,77
Referências:
NET - Unit of Work - Padrão Unidade de ...
NET - O padrão de projeto Decorator
NET - Padrão de Projeto Builder
C# - O Padrão Strategy (revisitado)
NET - O padrão de projeto Command
NET - Apresentando o padrão Repository