Às vezes, nesse tipo de hierarquia há certas operações aplicáveis ao objeto "todo" que podem também fazer sentido se aplicadas às partes isoladamente. Um exemplo clássico desse cenário é ter um objeto Desenho composto por elementos gráficos como linhas, círculos, triângulos, etc. O Desenho terá operações como "pintar-se", "redimensionar-se" e "mover-se" e estas mesmas operações podem ser aplicadas a cada uma das partes de forma independente.
O objetivo do Design Pattern estrutural Composite é justamente esse : permitir que classes Clientes possam tratar objetos individuais ou composições desse objeto de forma uniforme, podendo aplicar operações no todo ou em partes dele sem se preocupar se o objeto é de um tipo ou de outro. Um exemplo aplicável num ERP como o da ABC71 é a ideia de contratos. Os Contratos são compostos por Cláusulas e tanto o Contrato quanto suas Cláusulas individuais podem ser alteradas, revogadas ou perder validade.
Veja o diagram UML para esse Pattern.
A nomenclatura para as classes participantes de uma solução do tipo Composite é a seguinte :




O mapeamento desse padrão usando Delphi é feito através de heranças simples. Para facilitar o tratamento de lista na classe Composite, pode-se usar internamente a própria classe TList da VCL.
type
TWClausulaContrato = class
{ ... }
procedure Cancelar;virtual;
procedure Aplicar;virtual;
function EstaValido : boolean;virtual;
procedure Add (AElem : TWClausulaContrato);virtual;abstract;
procedure Remove (AElem : TWClausulaContrato);virtual;abstract;
function ItemAt ( AIndex : Integer) : TWClausulaContrato;virtual;abstract;
end;
TWClausula = class(TWClausulaContrato)
{ ... }
procedure Cancelar;override;
procedure Aplicar;override;
function EstaValido : boolean;override;
procedure Add (AElem : TWClausulaContrato);override;
procedure Remove (AElem : TWClausulaContrato);override;
function ItemAt ( AIndex : Integer) : TWClausulaContrato;override;
end;
TWContrato = class(TWClausulaContrato)
{ ... }
_Clausulas : TList;
procedure Cancelar;override;
procedure Aplicar;override;
function EstaValido : boolean;override;
procedure Add (AElem : TWClausulaContrato);override;
procedure Remove (AElem : TWClausulaContrato);override;
function ItemAt ( AIndex : Integer) : TWClausulaContrato;override;
end;
TWClausulaContrato = class
{ ... }
procedure Cancelar;virtual;
procedure Aplicar;virtual;
function EstaValido : boolean;virtual;
procedure Add (AElem : TWClausulaContrato);virtual;abstract;
procedure Remove (AElem : TWClausulaContrato);virtual;abstract;
function ItemAt ( AIndex : Integer) : TWClausulaContrato;virtual;abstract;
end;
TWClausula = class(TWClausulaContrato)
{ ... }
procedure Cancelar;override;
procedure Aplicar;override;
function EstaValido : boolean;override;
procedure Add (AElem : TWClausulaContrato);override;
procedure Remove (AElem : TWClausulaContrato);override;
function ItemAt ( AIndex : Integer) : TWClausulaContrato;override;
end;
TWContrato = class(TWClausulaContrato)
{ ... }
_Clausulas : TList;
procedure Cancelar;override;
procedure Aplicar;override;
function EstaValido : boolean;override;
procedure Add (AElem : TWClausulaContrato);override;
procedure Remove (AElem : TWClausulaContrato);override;
function ItemAt ( AIndex : Integer) : TWClausulaContrato;override;
end;
Para a classe TWClausula, as funções de gerenciamento não fazem nada - embora seja comum classes Leaf reportarem mensagens de erro para reforçar que elas não comportam filhos.
procedure TWClausula.Add (AElem : TWClausulaContrato);
begin
end;
procedure TWClausula.Remove (AElem : TWClausulaContrato);
begin
end;
function TWClausula.ItemAt ( AIndex : Integer) : TWClausulaContrato;
Result := Nil;
end;
begin
end;
procedure TWClausula.Remove (AElem : TWClausulaContrato);
begin
end;
function TWClausula.ItemAt ( AIndex : Integer) : TWClausulaContrato;
Result := Nil;
end;
Para a classe TWContrato, uso o TList para armazenar os filhos, sem importar se o novo elemento é uma cláusula simples ou um contrato mais complexo.
procedure TWContrato.Add (AElem : TWClausulaContrato);
begin
_Clausulas.Add (AElem);
end;
procedure TWContrato.Remove (AElem : TWClausulaContrato);
begin
_Clausulas.Remove (AElem);
end;
function TWContrato.ItemAt ( AIndex : Integer) : TWClausulaContrato;
Result := TWClausulaContrato(_Clausulas.Items[AIndex]);
end;
begin
_Clausulas.Add (AElem);
end;
procedure TWContrato.Remove (AElem : TWClausulaContrato);
begin
_Clausulas.Remove (AElem);
end;
function TWContrato.ItemAt ( AIndex : Integer) : TWClausulaContrato;
Result := TWClausulaContrato(_Clausulas.Items[AIndex]);
end;
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.