|
Software Development Kit to the Delphi-Win32 and Free Pascal compilers |
| Home > Wiki > br/ProjetoAgenda/Artigo2 |
br/ProjetoAgenda/Artigo2english (en) | português (pt)
Neste artigo será feita a implementação da parte lógica do projeto.
[edit] Objetos de negócioAs classes de negócio da aplicação serão declaradas juntas, separadas por grupo. Cada subpasta dentro da pasta Core terá apenas uma unit com todas as classes de negócio daquele grupo. [edit] CustomBOCrie a unit (sem form) {agenda}\Source\Core\Custom\CustomBO.pas e coloque o seguinte conteúdo: unit CustomBO; interface uses PressSubject, PressAttributes; type TCustomObject = class(TPressObject) end; TCustomQuery = class(TPressQuery) end; TCustomParts = class(TPressParts) end; TCustomReferences = class(TPressReferences) end; implementation initialization TCustomObject.RegisterClass; TCustomQuery.RegisterClass; TCustomParts.RegisterAttribute; TCustomReferences.RegisterAttribute; finalization TCustomObject.UnregisterClass; TCustomQuery.UnregisterClass; TCustomParts.UnregisterAttribute; TCustomReferences.UnregisterAttribute; end. O objetivo destas classes é figurar entre as classes do PressObjects e as classes de negócio da aplicação, para que seja possível incluir ou alterar funcionalidades de forma global e sem precisar alterar cada classe. [edit] ContatoBOCrie outra unit (também sem form) {agenda}\Source\Core\Contato\ContatoBO.pas e coloque o seguinte conteúdo:
unit ContatoBO;
interface
uses
PressSubject, PressAttributes, CustomBO;
type
{$M+} // necessário no FPC
TContatoFoneParts = class;
{$M-} // necessário no FPC
TContato = class(TCustomObject)
_Nome: TPressAnsiString;
_Endereco: TPressAnsiString;
_Fones: TContatoFoneParts;
_Cidade: TPressReference;
protected
class function InternalMetadataStr: string; override;
end;
TContatoQuery = class(TCustomQuery)
_Nome: TPressAnsiString;
_Cidade: TPressReference;
protected
class function InternalMetadataStr: string; override;
end;
TTipoFone = (tfFixo, tfCelular, tfFax);
TContatoFone = class(TCustomObject)
_TipoFone: TPressEnum;
_Numero: TPressPlainString;
protected
class function InternalMetadataStr: string; override;
end;
TContatoFoneParts = class(TCustomParts)
public
class function ValidObjectClass: TPressObjectClass; override;
end;
TCidade = class(TCustomObject)
_Nome: TPressAnsiString;
_UF: TPressAnsiString;
protected
class function InternalMetadataStr: string; override;
end;
TCidadeQuery = class(TCustomQuery)
_Nome: TPressAnsiString;
protected
class function InternalMetadataStr: string; override;
end;
implementation
initialization
PressModel.RegisterEnumMetadata(TypeInfo(TTipoFone), 'TTipoFone',
['Fone fixo', 'Celular', 'Fax']);
TContato.RegisterClass;
TContatoQuery.RegisterClass;
TContatoFone.RegisterClass;
TContatoFoneParts.RegisterAttribute;
TCidade.RegisterClass;
TCidadeQuery.RegisterClass;
finalization
TContato.UnregisterClass;
TContatoQuery.UnregisterClass;
TContatoFone.UnregisterClass;
TContatoFoneParts.UnregisterAttribute;
TCidade.UnregisterClass;
TCidadeQuery.UnregisterClass;
end.
Para implementar o metadata das classes de negócio, posicione o cursor de texto dentro da declaração da classe e pressione Shift + Ctrl + C. No método criado pela IDE, digite o seguinte bloco para a classe TContato:
class function TContato.InternalMetadataStr: string;
begin
Result := 'TContato IsPersistent (' +
'Nome: AnsiString(60);' +
'Endereco: AnsiString(80);' +
'Fones: TContatoFoneParts;' +
'Cidade: Reference(TCidade);' +
')';
end;
Esta é a parte mais importante da declaração da classe. O PressObjects irá interpretar esta string e criar os atributos com base nestas informações. Os membros de classe iniciados com "_" receberão o endereço destes atributos assim que o objeto for instanciado. Agora basta fazer o mesmo para as demais classes:
begin
Result := 'TContatoQuery(TContato) (' +
'Nome: AnsiString(60);' +
'Cidade: Reference(TCidade);' +
')';
end;
begin
Result := 'TContatoFone IsPersistent (' +
'TipoFone: Enum(TTipoFone);' +
'Numero: PlainString(15);' +
')';
end;
class function TContatoFoneParts.ValidObjectClass: TPressObjectClass; begin Result := TContatoFone; end;
begin
Result := 'TCidade IsPersistent (' +
'Nome: AnsiString(60);' +
'UF: AnsiString(2);' +
')';
end;
begin
Result := 'TCidadeQuery(TCidade) (' +
'Nome: AnsiString(60);' +
')';
end;
[edit] MVPAs classes MVP também serão agrupadas, cada subpasta dentro da pasta Core terá apenas uma unit com todas as suas classes MVP. [edit] MainMVPCrie a unit (sem form) {agenda}\Source\Core\Main\MainMVP.pas e coloque o seguinte conteúdo:
unit MainMVP;
interface
uses
PressMVPPresenter;
type
TMainFormPresenter = class(TPressMVPMainFormPresenter)
protected
procedure InitPresenter; override;
end;
implementation
end.
Utilizando o mesmo artifício da unit ContatoBO, posicione o cursor de texto em frente a declaração da classe TMainFormPresenter e pressione Shift + Ctrl + C. Dentro da declaração InitPresenter, implemente:
procedure TMainFormPresenter.InitPresenter;
begin
inherited;
BindPresenter(TContatoEditPresenter, 'NovoContatoButton');
BindPresenter(TContatoQueryPresenter, 'PesqContatoButton');
BindPresenter(TCidadeQueryPresenter, 'PesqCidadeButton');
BindCommand(TPressMVPCloseApplicationCommand, 'FecharButton');
PressUserData.Logon('', '');
end;
BindPresenter é um método que faz a ligação entre uma classe presenter e um componente, e o método BindCommand faz o mesmo com um command. Quando o evento OnClick destes componentes são acionados, o Presenter é executado e apresenta um form, ou o command é disparado. O método Logon cria um usuário com privilégio de uso de todos os commands, e será substituido logo que o controle de acesso for implementado. Estas declarações exigem algumas units: implementation uses PressUser, PressMVPCommand, ContatoMVP; Este Presenter deve ser executado na inicialização da aplicação, é ele quem iniciará alguns serviços internos do PressObjects. Abra o arquivo principal do projeto - Project | View Source (Delphi e Lazarus) - e inclua a chamada a este presenter: begin Application.Initialize; Application.CreateForm(TMainForm, MainForm); TMainFormPresenter.Run; end. A declaração TMainFormPresenter.Run ficará no lugar do tradicional Application.Run. Salve todos os arquivos do projeto. [edit] CustomMVPCrie a unit (sem form) {agenda}\Source\Core\Custom\CustomMVP.pas e coloque o seguinte conteúdo:
unit CustomMVP;
interface
uses
PressMVPPresenter;
type
TCustomEditPresenter = class(TPressMVPFormPresenter)
protected
procedure InitPresenter; override;
end;
TCustomQueryPresenter = class(TPressMVPQueryPresenter)
protected
procedure InitPresenter; override;
end;
implementation
initialization
TCustomEditPresenter.RegisterBO(TCustomObject);
TCustomQueryPresenter.RegisterBO(TCustomQuery);
end.
Utilizando o mesmo artifício das units anteriores, posicione o cursor de texto em frente a declaração da classe TCustomEditPresenter e pressione Shift + Ctrl + C. Dentro da declaração InitPresenter, implemente: procedure TCustomEditPresenter.InitPresenter; begin inherited; BindCommand(TPressMVPSaveObjectCommand, 'GravarButton'); BindCommand(TPressMVPCancelConfirmObjectCommand, 'CancelarButton'); end; Estas instruções ligam um determinado command a um componente do form. Ao pressionar o botão, o command é executado e irá, respectivamente, gravar o objeto no banco e fechar o form, ou reverter as alterações feitas no objeto em memória e fechar o form. Próxima classe, TCustomQueryPresenter. Posicione o cursor, pressione Shift + Ctrl + C e implemente:
procedure TCustomQueryPresenter.InitPresenter;
begin
inherited;
BindCommand(TPressMVPExecuteQueryCommand, 'PesquisarButton');
CreateQueryItemsPresenter('QueryStringGrid');
end;
A primeira instrução liga um command padrão do Press ao botão de pesquisa. A segunda é uma instrução especial de Presenters de pesquisa, e indica ao framework MVP qual é o componente que irá apresentar o resultado da consulta. Estas implementações dependem de declarações feitas em outras units. A cláusula uses da área implementation deve ficar assim: uses PressMVPCommand, CustomBO; [edit] ContatoMVPCrie a unit (sem form) {agenda}\Source\Core\Contato\ContatoMVP.pas e coloque o seguinte conteúdo:
unit ContatoMVP;
interface
uses
CustomMVP;
type
TContatoEditPresenter = class(TCustomEditPresenter)
protected
procedure InitPresenter; override;
end;
TContatoQueryPresenter = class(TCustomQueryPresenter)
protected
procedure InitPresenter; override;
function InternalQueryItemsDisplayNames: string; override;
end;
TContatoFoneEditPresenter = class(TCustomEditPresenter)
protected
procedure InitPresenter; override;
end;
TCidadeEditPresenter = class(TCustomEditPresenter)
protected
procedure InitPresenter; override;
end;
TCidadeQueryPresenter = class(TCustomQueryPresenter)
protected
procedure InitPresenter; override;
function InternalQueryItemsDisplayNames: string; override;
end;
implementation
uses
ContatoBO;
initialization
TContatoEditPresenter.RegisterBO(TContato);
TContatoQueryPresenter.RegisterBO(TContatoQuery);
TContatoFoneEditPresenter.RegisterBO(TContatoFone);
TCidadeEditPresenter.RegisterBO(TCidade);
TCidadeQueryPresenter.RegisterBO(TCidadeQuery);
end.
Agora falta o mapeamento entre as classes de negócio e os formulários. Com ajuda do Shift + Ctrl + C, implemente os seguintes códigos:
procedure TContatoEditPresenter.InitPresenter;
begin
inherited;
CreateSubPresenter('Nome', 'NomeEdit');
CreateSubPresenter('Endereco', 'EnderecoEdit');
CreateSubPresenter('Fones', 'FonesStringGrid', 'TipoFone;Numero');
CreateSubPresenter('Cidade', 'CidadeComboBox', 'Nome');
end;
O método CreateSubPresenter cria um presenter e respectivos views e models. O parâmetro indica respectivamente o nome do atributo na classe de negócio e o nome do componente no form. O terceiro parâmetro, usado em composições e agregações, indica qual ou quais atributos da outra classe devem ser apresentados no controle.
procedure TContatoQueryPresenter.InitPresenter;
begin
inherited;
CreateSubPresenter('Nome', 'NomeEdit');
CreateSubPresenter('Cidade', 'CidadeComboBox', 'Nome');
end;
function TContatoQueryPresenter.InternalQueryItemsDisplayNames: string; begin Result := 'Nome;Cidade.Nome'; end;
procedure TContatoFoneEditPresenter.InitPresenter;
begin
inherited;
CreateSubPresenter('TipoFone', 'TipoFoneComboBox');
CreateSubPresenter('Numero', 'NumeroEdit');
end;
procedure TCidadeEditPresenter.InitPresenter;
begin
inherited;
CreateSubPresenter('Nome', 'NomeEdit');
CreateSubPresenter('UF', 'UFEdit');
end;
procedure TCidadeQueryPresenter.InitPresenter;
begin
inherited;
CreateSubPresenter('Nome', 'NomeEdit');
end;
function TCidadeQueryPresenter.InternalQueryItemsDisplayNames: string; begin Result := 'Nome;UF'; end; [edit] Testando o projetoDê um Save All e um Build All no projeto para corrigir os erros de compilação. Execute o projeto, pressione Shift + Alt + 9 para gerar o metadata do banco de dados e abra todos os forms para testar os bindings, mas não tente gravar nada ainda. Obs.: forms e controles possuem menu de contexto (popup) acionados com o botão direito. Neste menu estão os atalhos usados para incluir, alterar, apagar, etc. as informações daquele componente. Se tudo correr bem, siga para o próximo artigo. Em caso de problema revise as implementações, nomes de forms e units, e os parâmetros dos bindings conforme a mensagem de erro apresentada.
|
Personal tools |