17 de dezembro de 2010

Design Patterns em Delphi - Mediator - parte II

Dada a natureza do problema abordado pelo Design Pattern comportamental Mediator, normalmente a implementação de uma solução com ele resulta numa hierarquia de classes bastante extensa. Basta lembrar que o conceito é aplicável ao conjunto de telas (Forms) de um sistema, onde cada nova tela herdada é um mediador e os componentes inseridos nela podem conversar entre si de maneiras específicas, sem que as classes de componentes necessitem ter conhecimneto umas das outras. O conceito do Mediator foi introduzido num post em novembro, acessível neste link. Apenas para relembrar o básico: o Mediator propõe centralizar em uma única classe base a responsabilidade pela comunicação de todas as outras envolvidas na solução de um problema.

Isto posto, pretendo mostrar aqui a implementação de um exemplo simples, proposto naquele post inicial. É o exemplo da torre de controle de tráfego aéreo, onde a comunicação entre os participantes pode ser implementada de uma forma mais genérica, fazendo com que seja necessária apenas uma herança do mediador. Segue uma reprodução do diagrama UML com o exemplo proposto:
Diagrama UML para o padrão Mediator
Começo a codificação pela interface que estabelece as regras de mediação, isto é, o próprio Mediator. Ela é normalmente assentada como uma classe abstrata a partir da qual todas as possibilidades de mediação são herdadas.
TWFila = class
public
procedure push (obj: TObject);
function pop : TObject;
end;

TWAeronaveAbstrata = class;

TWTorreAbstrata = class
public
procedure concedePermissao(Aeron: TWAeronaveAbstrata); virtual;abstract;
procedure solicitaPouso (Aeron: TWAeronaveAbstrata); virtual;abstract;
procedure solicitaDecolagem (Aeron: TWAeronaveAbstrata); virtual;abstract;
end;

TWTorreAeroportoCGN = class(TWTorreAbstrata)
protected
_FilaPista : TWFila;

public
procedure concedePermissao(Aeron: TWAeronaveAbstrata); override;
procedure solicitaPouso (Aeron: TWAeronaveAbstrata); override;
procedure solicitaDecolagem (Aeron: TWAeronaveAbstrata); override;
end;

No exemplo, há apenas uma herança mas o mais comum é ter que trabalhar com diversas delas, como no caso de se usar telas como mediadores para gerenciar a comunicação entre os elementos de interface visual presentes (os componentes da tela). A classe TWFila é apenas auxiliar, sendo usada aqui para controlar a fila de aeronaves que solicitarem algum procedimento à torre. Num projeto real, é praticamente regra que tenhamos neste ponto instâncias de classes específicas cuja comunicação será mediada, implementando regras de negócio únicas. Por causa disso, cada herança do mediador é normalmente aplicada a um único cenário predeterminado.

A declaração dos Colleagues (objetos cuja comunicação é mediada) também é bem direta:
TWAeronaveAbstrata = class
protected
_Aguardando: boolean;
_Torre: TWTorreAbstrata;
public
constructor Create (ATorre: TWTorreAbstrata);

function aguardarPermissao : boolean; virtual;abstract;
procedure pousar; virtual;abstract;
procedure decolar; virtual;abstract;
procedure liberarPista; virtual;abstract;
end;

TWJatoExecutivo = class(TWAeronaveAbstrata)
public
constructor Create (ATorre: TWTorreAbstrata);

function aguardarPermissao : boolean; override;
procedure pousar; override;
procedure decolar; override;
procedure liberarPista; override;
end;

O único ponto importante a ressaltar é a existência do membro _Torre, que é uma instância da classe mediadora. Isso reforça o conceito de que a comunicação entre os diversos tipos de Colleagues deve ser levada a cabo exclusivamente através do mediador, isto é, nenhum Colleague deve ter conhecimento da existência dos demais. Como estas classes são fracamente acopladas, podemos introduzir novos Colleagues sem prejuízo para as heranças já estabelecidas na solução.

O trecho abaixo mostra um exemplo da comunicação usando o mediador.
procedure TWJatoExecutivo.pousar;
begin
{ Solicita autorização à torre e aguarda permissão }
_Aguardando := true;
_Torre.solicitarPouso ();

While (aguardarPermissao() ) do
Sleep (1000);

{ Com a permissão concedida, a pista é liberada para o procedimento da aeronave seguinte }
liberarPista;
end;

Este é um exemplo bastante simples, com as instâncias das classes do tipo Colleague inseridas numa fila. De novo : no mundo real, teríamos instâncias específicas dessas classes enviando mensagens umas às outras. Por fim, as classes representando aeronaves são muito parecidas entre si e, por isso, inclui neste post a declaração de apenas uma delas, omitindo as demais.

Nenhum comentário :

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.