O livro "JAVA and Patterns" do Dr. Yan Hong começa com uma descrição do padrão Mediator:
O padrão mediador é o padrão de comportamento dos objetos. O padrão Mediator resume a forma como um conjunto de objetos interage para que eles não precisem fazer referência explícita um ao outro. Isso permite que eles sejam fracamente acoplados. Quando as interações entre alguns desses objetos mudam, isso não afeta imediatamente as interações entre outros objetos. Isso garante que essas interações possam variar independentemente umas das outras.
Por que um mediador é necessário
Conforme mostrado na figura abaixo, há um grande número de objetos neste diagrama esquemático. Esses objetos podem afetar outros objetos e ser afetados por outros objetos, por isso são frequentemente chamados de objetos Colega. Esses colegas de trabalho formam o comportamento do sistema por meio de sua interação entre si. Como pode ser visto na figura, quase todos os objetos precisam interagir com outros objetos, e essa interação se manifesta como um acoplamento direto entre um objeto e outro objeto. Este é um sistema sobreacoplado.
Ao introduzir o objeto mediador (Mediador), a estrutura de rede do sistema pode ser transformada em uma estrutura em estrela centrada no mediador, conforme mostrado na figura abaixo. Nesta estrutura em estrela, um objeto colega não interage mais com outro objeto por meio de uma conexão direta; em vez disso, ele interage com outro objeto por meio de um objeto mediador. A existência do objeto mediador garante a estabilidade da estrutura do objeto, ou seja, a estrutura do sistema não causará muitos trabalhos de modificação devido à introdução de novos objetos.
Um bom design orientado a objetos pode aumentar a colaboração e reduzir o acoplamento entre objetos. Um design bem pensado divide um sistema em um grupo de objetos de colegas de trabalho cooperantes e, em seguida, atribui responsabilidades exclusivas a cada objeto de colega de trabalho e configura adequadamente os relacionamentos colaborativos entre eles para que possam trabalhar juntos.
Se não houver placa-mãe
Como todos sabemos, a interação entre os diversos acessórios do computador é feita principalmente através da placa-mãe. Se não houver placa-mãe no computador, os vários acessórios deverão interagir entre si para transmitir dados entre si. E como as interfaces de cada acessório são diferentes, ao interagirem entre si, a interface de dados deve ser convertida para corresponder.
Felizmente, com a placa-mãe, a interação dos diversos acessórios é totalmente completada através da placa-mãe. Cada acessório só precisa interagir com a placa-mãe, e a placa-mãe sabe lidar com todos os acessórios, o que torna tudo muito mais simples.
A estrutura do padrão mediador
Um diagrama de classes esquemático para o padrão Mediator é mostrado abaixo:
O modo mediador inclui as seguintes funções:
● Papel do mediador abstrato (Mediador): Define a interface do objeto colega para o objeto mediador, no qual o método principal é um (ou mais) métodos de evento.
● Função Mediador Concreto (ConcreteMediator): implementa o método de evento declarado pelo mediador abstrato. O mediador específico está ciente de todas as classes específicas de colegas e é responsável por coordenar especificamente a interação entre cada objeto colega.
● Função da classe abstrata de colega (Colleague): define a interface do mediador para o objeto colega. Os objetos colegas só conhecem o mediador e não os demais objetos colegiais.
● Função ConcreteColleague: todas as classes concretas de colegas herdam da classe abstrata de colegas. Para implementar o seu próprio negócio, quando necessitar de comunicar com outros colegas, comunique com o mediador que o detém. O mediador será responsável pela interação com os restantes colegas.
código fonte
O código de cópia da classe mediadora abstrata é o seguinte:
interface pública Mediador {
/**
* O objeto colega notifica o método mediador quando ele muda.
* Deixe o mediador ser responsável pelas interações correspondentes com outros objetos colegas
*/
vazio público alterado (colega c);
}
classe de mediador concreto
Copie o código do código da seguinte forma:
classe pública ConcreteMediator implementa Mediator {
//Segure e mantenha o colega A
private ConcreteColleagueA colegaA;
//Segure e mantenha o colega B
private ConcreteColleagueB colegaB;
public void setColleagueA(ConcreteColleagueA colegaA) {
este.colegaA = colegaA;
}
public void setColleagueB(ConcreteColleagueB colegaB) {
este.colegaB = colegaB;
}
@Substituir
public void alterado(colega c) {
/**
* Uma determinada turma de colega mudou, geralmente exigindo interação com outros colegas
* Coordene especificamente os objetos de colegas correspondentes para alcançar um comportamento colaborativo
*/
}
}
aula abstrata de colega
Copie o código do código da seguinte forma:
classe abstrata pública Colega {
//Mantém um objeto mediador
mediador mediador privado;
/**
*Construtor
*/
Colega público(Mediador mediador){
este.mediador = mediador;
}
/**
* Obtenha o objeto mediador correspondente à classe do colega atual
*/
mediador público getMediator() {
mediador de retorno;
}
}
O código específico para copiar a mesma classe é o seguinte:
classe pública ConcreteColleagueA estende Colega {
public ConcreteColleagueA(Mediador mediador) {
super(mediador);
}
/**
*Indique métodos para realizar determinadas operações
*/
operação pública nula(){
//Notifica o objeto mediador quando precisar se comunicar com outros colegas
getMediator().changed(this);
}
}
Copie o código do código da seguinte forma:
classe pública ConcreteColleagueB estende Colega {
public ConcreteColleagueB(Mediador mediador) {
super(mediador);
}
/**
*Indique métodos para realizar determinadas operações
*/
operação pública nula(){
//Notifica o objeto mediador quando precisar se comunicar com outros colegas
getMediator().changed(this);
}
}
Use seu computador para assistir filmes
Na vida cotidiana, costumamos usar computadores para assistir filmes. Vamos descrever esse processo. Após simplificação, assumimos que haverá o seguinte processo interativo:
(1) Primeiro, a unidade óptica precisa ler os dados do disco óptico e, em seguida, informar à placa-mãe que seu status mudou.
(2) A placa-mãe obtém os dados da unidade óptica e os entrega à CPU para análise e processamento.
(3) Depois que a CPU termina o processamento, ela divide os dados em dados de vídeo e dados de áudio e notifica a placa-mãe de que o processamento foi concluído.
(4) A placa-mãe obtém os dados processados pela CPU e os passa para a placa gráfica e placa de som respectivamente para exibir o vídeo e emitir sons.
Para implementar o exemplo usando o padrão mediador, é necessário distinguir entre objetos colegas e objetos mediadores. Obviamente, a placa-mãe é a mediadora, e acessórios como unidades ópticas, placas de som, CPUs e placas gráficas são todos colegas.
código fonte
O código abstrato de cópia da classe colega é o seguinte:
classe abstrata pública Colega {
//Mantém um objeto mediador
mediador mediador privado;
/**
*Construtor
*/
Colega público(Mediador mediador){
este.mediador = mediador;
}
/**
* Obtenha o objeto mediador correspondente à classe do colega atual
*/
mediador público getMediator() {
mediador de retorno;
}
}
Classe de colega - o código de cópia da unidade óptica é o seguinte:
classe pública CDDriver estende Colega{
//Dados lidos da unidade óptica
dados de string privados = "";
/**
*Construtor
*/
public CDDriver(Mediador mediador) {
super(mediador);
}
/**
* Obtenha os dados lidos do disco
*/
string pública getDados() {
retornar dados;
}
/**
* Leia CD
*/
public void readCD(){
//Antes da vírgula estão os dados exibidos no vídeo, e depois da vírgula está o som
this.data = "One Piece, estou determinado a ser o Rei dos Piratas";
//Notifica a placa-mãe que seu status mudou
getMediator().changed(this);
}
}
Classe de colega —— CPU
Copie o código do código da seguinte forma:
CPU de classe pública estende Colega {
//Dados de vídeo decompostos
private String videoData = "";
//Dados de som decompostos
string privada soundData = "";
/**
*Construtor
*/
CPU pública (mediador mediador) {
super(mediador);
}
/**
* Obtenha dados de vídeo decompostos
*/
public String getVideoData() {
retornar dados de vídeo;
}
/**
* Obtenha os dados sonoros decompostos
*/
string pública getSoundData() {
retornar dados de som;
}
/**
* Processe os dados e divida-os em dados de áudio e vídeo
*/
public void executeData(String dados){
//Decompõe os dados. A frente são os dados de vídeo e a parte traseira são os dados de áudio.
String[] array = data.split(",");
this.videoData = array[0];
this.soundData = array[1];
//Notifica a placa-mãe que a CPU concluiu o trabalho
getMediator().changed(this);
}
}
Classe de colega - o código de cópia da placa gráfica é o seguinte:
classe pública VideoCard estende Colega {
/**
*Construtor
*/
public VideoCard(Mediador mediador) {
super(mediador);
}
/**
* Exibir dados de vídeo
*/
public void showData(String dados){
System.out.println("Você está assistindo: " + dados);
}
}
Classe de colega - o código de cópia da placa de som é o seguinte:
classe pública SoundCard estende Colega {
/**
*Construtor
*/
public SoundCard(Mediador mediador) {
super(mediador);
}
/**
* Faça sons com base em dados de áudio
*/
public void soundData(dados de string){
System.out.println("Voiceover: " + dados);
}
}
O código de cópia da classe mediadora abstrata é o seguinte:
interface pública Mediador {
/**
* O objeto colega notifica o método mediador quando ele muda.
* Deixe o mediador ser responsável pelas interações correspondentes com outros objetos colegas
*/
vazio público alterado (colega c);
}
O código de cópia específico da classe mediadora é o seguinte:
classe pública MainBoard implementa Mediator {
//Precisa conhecer a classe do colega para interagir - a classe da unidade óptica
driver de CD privado cdDriver = null;
//Precisa conhecer a classe do colega para interagir com a classe CPU
CPU privada CPU = null;
//Precisa conhecer a classe de colegas com quem interagir - a classe da placa gráfica
placa de vídeo privada videoCard = null;
//Precisa conhecer a turma de colegas com quem interagir - a turma da placa de som
placa de som privada soundCard = null;
public void setCdDriver(CDDriver cdDriver) {
este.cdDriver = cdDriver;
}
public void setCpu(CPU CPU) {
isto.cpu = cpu;
}
public void setVideoCard(VideoCard videoCard) {
this.videoCard = videoCard;
}
public void setSoundCard(SoundCard soundCard) {
this.soundCard = soundCard;
}
@Substituir
public void alterado(colega c) {
if(c instância do driver de CD){
//Indica que a unidade óptica leu dados
this.opeCDDriverReadData((CDDriver)c);
}else if(c instância da CPU){
this.opeCPU((CPU)c);
}
}
/**
* Lidar com a interação com outros objetos depois que a unidade óptica lê os dados
*/
private void opeCDDriverReadData(CDDriver cd){
//Primeiro obtenha os dados lidos pela unidade óptica
String dados = cd.getData();
//Transfere esses dados para a CPU para processamento
cpu.executeData(dados);
}
/**
* Lidar com a interação entre a CPU e outros objetos após processar os dados
*/
privado vazio opeCPU(CPU CPU){
//Obtém primeiro os dados processados pela CPU
String videoData = cpu.getVideoData();
String soundData = cpu.getSoundData();
//Transfere esses dados para a placa gráfica e placa de som para exibição
videoCard.showData(videoData);
soundCard.soundData(soundData);
}
}
O código de cópia da classe cliente é o seguinte:
classe pública Cliente {
public static void main(String[] args) {
//Criar mediador - placa-mãe
Mediador MainBoard = new MainBoard();
//Cria classe de colega
CDDriver cd = novo CDDriver(mediador);
CPU CPU = nova CPU(mediador);
VideoCard vc = new VideoCard(mediador);
SoundCard sc = new SoundCard(mediador);
//Avise ao mediador todos os colegas
mediador.setCdDriver(cd);
mediador.setCpu(cpu);
mediador.setVideoCard(vc);
mediador.setSoundCard(sc);
//Comece a assistir o filme, coloque o disco na unidade óptica e a unidade óptica começa a ler o disco
cd.readCD();
}
}
Os resultados da execução são os seguintes:
Vantagens do Padrão Mediador
● acoplamento solto
O padrão mediador encapsula as interações entre vários objetos colegas no objeto mediador, acoplando assim fracamente os objetos colegas e basicamente alcançando dependências complementares. Desta forma, os objetos dos colegas podem ser alterados e reutilizados de forma independente, em vez de “mover um lugar e afetar todo o corpo” como antes.
● Controle centralizado de interações
As interações de vários objetos colegas são encapsuladas no objeto mediador para gerenciamento centralizado, de modo que quando esses comportamentos interativos mudam, você só precisa modificar o objeto mediador. Claro, se for um sistema já concluído, então expanda o objeto mediador, e cada classe de colega não precisa ser modificada.
● Muitos para muitos torna-se um para muitos
Quando o padrão mediador não é usado, o relacionamento entre objetos colegas geralmente é muitos para muitos. Depois que o objeto mediador é introduzido, o relacionamento entre o objeto mediador e o objeto colega geralmente se torna um para muitos bidirecional. o que torna o relacionamento entre os objetos mais fácil de entender e implementar.
Desvantagens do Padrão Mediador
Uma desvantagem potencial do modelo mediador é a centralização excessiva. Se a interação dos objetos colegas for muito grande e complexa, quando todas essas complexidades estiverem concentradas no mediador, o objeto mediador se tornará muito complexo e difícil de gerenciar e manter.