SlideShare una empresa de Scribd logo
1 de 18
Descargar para leer sin conexión
Orientação a Objetos no Delphi: Controle de Estoque – Parte II
Ryan Bruno C Padilha
ryan.padilha@gmail.com
http://ryanpadilha.com.br
Objetivo deste artigo
Este artigo é o segundo de uma série de três artigos onde abordamos o paradigma orientado a
objetos. No primeiro artigo foi introduzido os principais conceitos da orientação a objetos,
sempre comparando a OO com o modelo de programação estrutural, permitindo assim ao
leitor uma maior reflexão sobre o que seria interessante utilizar em projetos de software.
Nesta segunda parte iniciaremos a construção de uma aplicação de controle de estoque
básico, empregando todos os conceitos anteriormente abordados, provando na prática que a
OO é viável, e até mesmo recomendada para projetos de média e grande complexidade.
Utilizaremos este exemplo prático como referência, ou seja, uma orientação para o
desenvolvimento de futuras aplicações, que poderão empregar todos os recursos que a
orientação a objetos nos proporciona.
1. Descrição do Modelo Conceitual
Ao iniciar um projeto de software abordando o paradigma orientado a objetos, seria
interessante começarmos o processo de desenvolvimento através da modelagem das classes
de negócios, identificando os elementos que fazem parte da aplicação. A modelagem pode ser
realizada através da notação UML (Unified Modeling Language), que oferece um modelo de
diagrama ideal para modelagem de classes – o diagrama de classe - do qual irá conter toda a
lógica de interações entre os objetos que compõe o escopo do projeto. Nesta série sobre OO
somente será adotado o diagrama de classes, considerado “a espinha dorsal” da UML e
amplamente difundido entre os desenvolvedores, de fácil entendimento e utilização.
Conforme citado no primeiro artigo, uma boa ferramenta para realizarmos a modelagem de
classes, é o software Judy Community, que pode ser encontrado em http://jude.change-
vision.com/jude-web/product/community.html.
Existem outros diagramas na UML que poderiam ser adotados na modelagem da aplicação.
São separados por categorias: 1) Diagramas Estruturais de: objeto, componentes, instalação,
pacote, estrutura e classe; 2) Diagramas Comportamentais de: caso de uso, estado e
atividade; 3) Diagrama de Interação (comportamentais) de: seqüência, interatividade,
colaboração e sincronização.
Muitos desenvolvedores neste momento podem se perguntar: o que é um controle de
estoque? O controle de estoque tem como objetivo otimizar o investimento em estoques,
aumentar o uso eficiente dos meios internos de uma empresa e minimizar as necessidades de
capital investido em estoque. É uma área fundamental da empresa, pois através dela somos
capazes de prever o quanto será necessário comprar de um determinado produto, além de
outras informações úteis sobre as vendas, e a movimentação de entrada / saída de produtos
do estoque. Os elementos básicos de uma aplicação de controle de estoque estão
relacionados abaixo.
Trabalharemos com o domínio de uma aplicação voltada para o controle de estoque de
produtos representado pela figura 1, que possui as seguintes classes: Endereco, Pessoa (classe
abstrata), PessoaJ (classe abstrata), Empesa, Estoque, Pedido, Entrada, Produto, Marca,
Unidade e Categoria. Observamos a presença da declaração de atributos e métodos em cada
classe – os atributos possuem o modificador de visibilidade private, reforçando o conceito de
encapsulamento de atributos, através de métodos acessores do tipo getter e setter
(retornando e atribuindo valores, respectivamente), alterando o estado do objeto instanciado.
Os métodos acessores são utilizados na declaração Property (propriedade), sobrecarregando
as operações de leitura (read) e escrita (write) executadas quando a propriedade for acessada.
A declaração citada desempenha papel fundamental ao proteger o acesso ao objeto, definindo
uma forma padronizada de acesso ao estado do objeto (as propriedades e métodos
getters/setters foram omitidos do diagrama de classes apresentado na figura 1) . O atributo
TABLENAME é estático, cada classe concreta poderá (em nosso diagrama deve) possuir um
determinado nome de tabela, que deverá ser mapeado para uma tabela no modelo de banco
de dados objeto-relacional. Além dos métodos acessores sobrecarregados por Property, é
declarado e implementado um conjunto de métodos que realizam operações sobre o SGBD
(Sistema Gerenciador de Banco de Dados) executando comandos SQL/DML (Structured Query
Language/Data Manipulation Language):
1) SELECT – Selecionar objetos persistidos em uma tabela, serializando as colunas em atributos
de classe. Os métodos assinados como getObject(Id: String): boolean e getObjects(): boolean
recuperam objetos do SGBD;
2) INSERT – Persistir objetos em uma tabela, serializando seu atributos em colunas. O método
assinado como public Merge(): boolean verifica se o atributo código do objeto está com
presença de valor (diferente de vazio/0), se o mesmo não contiver nenhum valor o comando
INSERT será executado através da chamada do método private Insert(): boolean;
3) UPDATE – Atualizar objetos em uma tabela, que foram selecionados anteriormente (des-
serializados) e estão instanciados na memória principal; empregando um filtro WHERE que
dispõem de condições comparativas, neste caso usamos o identificador único do objeto, o Id
(código) que é chave primária da tabela onde o objeto está sendo recuperado/persistido. O
método assinado como public Merge(): boolean chamado para executar o comando INSERT é
utilizado também para a execução do comando UPDATE, se o atributo código do objeto
recuperado for consistente o método private Update(): boolean é invocado;
4) DELETE – Deletar objetos em uma tabela. Um objeto recuperado do SGBD e instanciado na
memória principal, pode ser excluído através da chamada do método Delete(): boolean
executando o comando DELETE. Usamos como referência o identificador único do objeto, o Id
(código), citado anteriormente.
O conjunto das quatro operações básicas relacionadas acima empregadas em SGBD objeto-
relacional, reconhecido como CRUD (acrônimo de Create, Retrieve, Update, Delete) é
implementado na maioria das aplicações que adotam o paradigma orientado a objetos. É
notado que o CRUD contém assinaturas de métodos comuns na maioria das classes concretas
em que estão implementados, e possuem comportamento semelhante - o de executar
instruções SQL. Poderemos em um próximo artigo descrever a arquitetura e implementar uma
biblioteca de classes que se relacionam entre si através de associações e composições, com a
finalidade de automatizar o processo de Mapeamento Objeto-Relacional ao adotar o
paradigma orientação a objetos. A tarefa de mapear objetos em entidade relacional é algo na
maioria das vezes repetitivo, onde serializamos e des-serializamos objetos, ou seja, mapeando
atributo-coluna / coluna-atributo em determinada tabela presente no Schema do usuário do
SGBD.
Figura 1 – Diagrama de classes simplificado. Domínio: Controle de Estoque.
2. Implementação em Object Pascal do diagrama de classes de domínio
Este exemplo tem finalidade educacional e pode ser modificado, alterado e distribuído. Caso
seja utilizado para fins didáticos por outras pessoas, preserve o nome do autor.
Como exemplo para esta série de artigos, criaremos uma aplicação conforme apresentado
pelo diagrama da figura 1. Adotamos a IDE Delphi 7 (mais nada impede a utilização de outras
versões do Delphi), o intuito é apresentar os conceitos da orientação a objetos através de uma
implementação de um software real, com a finalidade de controlar o estoque de produtos de
uma empresa do ramo varejista e/ou atacadista. Para realizar a persistência de objetos, ou
seja, efetuar a gravação permanente de objetos para a futura recuperação dos mesmos, e até
para manter um histórico de tudo o que ocorreu até hoje com o estoque de uma empresa, é
necessário a utilização de um SGBD.
O SGBD PostgreSQL 8.3, banco de dados objeto-relacional, é adotado neste exemplo por ser
open-source (não é necessário adquirir licença para utilizá-lo), de fácil instalação e
manutenção, robusto, confiável, flexível, rico em recursos, dentre outras características.
Oferece suporte a comandos complexos, chaves estrangeiras, gatilhos (triggers), visões,
integridade transacional, e controle de simultaneidade multiversão. Pode ser encontrado em
http://www.postgresql.org. Não será exibido aqui como instalar o PostgreSQL, sua instalação é
simples e rápida. Caso haja alguma dúvida em como efetuar a instalação, procure informações
em fóruns e websites especializados neste banco de dados.
Um ponto importante que deve ser analisado com cuidado é: qual componente de acesso a
dados pode ser utilizado para acessar os dados no PostgreSQL? Como muitos desenvolvedores
que estão lendo este artigo trabalham com diversos ambientes de banco de dados, é
interessante escolher um componente de acesso que ofereça uma maior flexibilidade e
facilidade durante a utilização e/ou migração de um banco de dados para outro. Tendo isto
como requisito básico de projeto, podemos utilizar a biblioteca ZeosLib que é open-source
(assim como o PostgreSQL), suporta conexão nativa e transparente, composto por um
conjunto de componentes de banco de dados que oferece suporte a diversos banco de dados:
MySQL, PostgreSQL, Firebird, MSSQL Server, Oracle e SQLite. Para quem ainda não tem o
ZeosLib instalado no Delphi, efetue o download em http://sourceforge.net/projects/zeoslib/,
durante a escrita deste artigo, a versão estável disponível para download do ZeosLib era
ZEOSDBO-6.6.6-stable, porém no exemplo que será desenvolvido foi utilizado a versão 6.6.2-
RC. Caso tenha alguma dúvida entre as diversas versões disponíveis e a diferença entre elas,
leia o File Releases do projeto ZeosLib. Sua instalação é relativamente simples, bastando seguir
um passo-a-passo no estilo “receita de bolo” e pronto. Para maiores detalhes sobre a
instalação veja em http://www.activedelphi.com.br/forum/viewtopic.php?t=33645. Não será
exibido aqui como instalar a biblioteca ZeosLib, pois pode ser encontrado no próprio Active
Delphi informações de como proceder.
Figura 2 – Biblioteca ZeosLib no Delphi 7 (aba ZeosAccess).
Após adquirir o SGBD PostgreSQL e o componente de acesso a dados ZeosLib instalados no
ambiente de trabalho, podemos iniciar o projeto de software. Com o Delphi aberto crie um
novo projeto chamado “ControleEstoque” (menu File – New – Application) e salve-o no
diretório “d:projetosoocontrole_estoque” ou escolha um local de sua preferência. No
formulário principal que é exibido na tela adicione o seguinte componente visual:
- TMainMenu: Adicione o menu Cadastros contendo os itens: Grupo de Empresas, Produtos.
Neste últimos criaremos um sub-menu contendo: Cadastro de Produto, Cadastro de Marca,
Cadastro de Unidade e Cadastro de Categoria. Adicione o menu Movimentação contendo o
item Movimentação de Estoque. E por último adiciona o menu Sobre.
A princípio estamos modelando a apresentação visual de nossa aplicação, definindo o
formulário principal e seu menu de navegação, que fornecerá acesso aos formulários da
aplicação que serão criados posteriormente. Dentro do diretório do projeto crie um diretório
“classes” – com a função de agrupar as classes de negócio implementadas no projeto; e outro
diretório “view” – utilizado com repositório de formulários construídos através do designer. Os
diretórios criados atuam como pacotes, armazenando código-fonte semelhantes, ou seja,
todas as nossas classes estarão contidas dentro de “classes” e os formulários dentro de “view”,
com isso obtemos uma maior organização. Se futuramente quisermos reaproveitar nossas
classes de negócios em outro projeto, será fácil localizar e compartilhar o mesmo código-fonte
com outro projeto de software que se beneficiaria da implementação realizada neste módulo
de controle de estoque, promovendo a reutilização de código – característica fundamental da
orientação a objetos.
2.1 Classes de negócio
No projeto de software modelamos as classes de negócio, cada classe é implementada em
uma unit, por exemplo a classe Endereco é definida na unit clEndereco e assim por diante. É
adotado uma convenção de código, definindo um padrão para a codificação, melhorando com
isso a legibilidade do código-fonte. Segue abaixo a convenção utilizada aqui:
1) clNomeUnit: define o nome da unit que contém a implementação da classe. Exemplo:
clEndereco, clPessoa, clPessoaJ, clEmpresa, clEstoque, clProduto.
2) TNomeClasse: define o nome da classe. Toda classe definida no Delphi inicia com a letra T.
Exemplo: TEndereco, TPessoa, TPessoaJ, TEmpresa, TEstoque, TProduto.
3) _nomeAtributo: define o nome de atributo. Exemplo: _codigo, _logradouro, _numero,
_nome.
4) NomeProperty: define o nome da propriedade. A primeira letra em maiúsculo e o restante
da palavra em minúsculo. Exemplo: Codigo, Logradouro, Numero, NomeComp.
Comecemos com a implementação da classe concreta Endereco, a responsabilidade dessa
classe é conter dados relacionado aos endereços da classe abstrata Pessoa. Adicione uma nova
unit ao projeto através de Menu File – New – Unit, salve a unit no diretório “classes” como
clEndereco.pas. No bloco interface/implementation da unit declare/implemente a classe
conforme abaixo:
unit clEndereco;
interface
type
TEndereco = class(TObject)
private
// métodos acessores suprimidos. getters / setters.
protected
// declaração de atributos
_codigo: String;
_logradouro: String;
_numero: String;
_complemento: String;
_cep: String;
_tipo: Integer;
_correspondencia: Boolean;
_referencia: String;
_bairro: String;
_cidade: String;
public
// declaração das propriedades da classe, encapsulamento de atributos
property Codigo: String read getCodigo write setCodigo;
property Logradouro: String read getLogradouro write setLogradouro;
property Numero: String read getNumero write setNumero;
property Complemento: String read getComplemento write setComplemento;
property Cep: String read getCEP write setCEP;
property Tipo: Integer read getTipo write setTipo;
property Correspondencia: Boolean read getCorrespondencia write setCorrespondencia;
property Referencia: String read getReferencia write setReferencia;
property Bairro: String read getBairro write setBairro;
property Cidade: String read getCidade write setCidade;
// nesta última linha pressione Ctrl + Shift + C
// para gerar os métodos acessores getters e setters automaticamente
// declaração de métodos
function Validar(): boolean;
function Merge(): Boolean;
function Delete(Filtro: String): Boolean;
function getObject(Id: String; Filtro: String): Boolean;
function Insert(Id: String; Tipo: String): Boolean;
function Update(Id: String): Boolean;
end;
const
TABLENAME = 'ENDERECO';
implementation
uses clUtil, SysUtils, dmConexao, DB, ZDataset, ZAbstractRODataset, Variants;
{ TEndereco }
function TEndereco.Delete(Filtro: String): Boolean;
begin
try
Result := False;
with Conexao.QryCRUD do begin
Close;
SQL.Clear;
SQL.Text := 'DELETE FROM '+ TABLENAME +' WHERE END_CODIGO =:CODIGO';
ParamByName('CODIGO').AsString := Self.Codigo;
ExecSQL;
end;
Result := True;
Except
on E : Exception do
ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message);
end;
end;
function TEndereco.getBairro: String;
begin
Result := _bairro;
end;
function TEndereco.getCEP: String;
begin
Result := _cep;
end;
function TEndereco.getCidade: String;
begin
Result := _cidade;
end;
function TEndereco.getCodigo: String;
begin
Result := _codigo;
end;
function TEndereco.getComplemento: String;
begin
Result := _complemento;
end;
function TEndereco.getCorrespondencia: Boolean;
begin
Result := _correspondencia;
end;
function TEndereco.getLogradouro: String;
begin
Result := _logradouro;
end;
function TEndereco.getNumero: String;
begin
Result := _numero;
end;
function TEndereco.getObject(Id: String; Filtro: String): Boolean;
begin
Try
Result := False;
if TUtil.Empty(Id) then
Exit;
with Conexao.QryGetObject do begin
Close;
SQL.Clear;
SQL.Add('SELECT * FROM '+ TABLENAME);
if filtro = 'ENDERECO' then begin
SQL.Add(' WHERE END_CODIGO =:CODIGO');
ParamByName('CODIGO').AsString := Id;
end
else if filtro = 'EMPRESA' then begin
SQL.Add(' WHERE EMP_CODIGO =:CODIGO');
ParamByName('CODIGO').AsString := Id;
end;
Open;
First;
end;
if Conexao.QryGetObject.RecordCount > 0 then begin
Self.Codigo := Conexao.QryGetObject.FieldByName('END_CODIGO').AsString;
Self.Logradouro := Conexao.QryGetObject.FieldByName('END_LOGRADOURO').AsString;
Self.Numero := Conexao.QryGetObject.FieldByName('END_NUMERO').AsString;
Self.Complemento := Conexao.QryGetObject.FieldByName('END_COMPLEMENTO').AsString;
Self.Bairro := Conexao.QryGetObject.FieldByName('END_BAIRRO').AsString;
Self.Cidade := Conexao.QryGetObject.FieldByName('END_CIDADE').AsString;
self.Cep := Conexao.QryGetObject.FieldByName('END_CEP').AsString;
Self.Referencia := Conexao.QryGetObject.FieldByName('END_PT_REFERENCIA').AsString;
Self.Tipo := Conexao.QryGetObject.FieldByName('END_TIPO').AsInteger;
Self.Correspondencia := Conexao.QryGetObject.FieldByName('END_CORRESP').AsBoolean;
Result := True;
end
else
ShowMessage('Registro não encontrado!');
Except
on E : Exception do
ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message);
end;
end;
function TEndereco.getReferencia: String;
begin
Result := _referencia;
end;
function TEndereco.getTipo: Integer;
begin
Result := _tipo;
end;
function TEndereco.Insert(Id: String; Tipo: String): Boolean;
begin
Try
Result := False;
with Conexao.QryCRUD do begin
Close;
SQL.Clear;
SQL.Text := 'INSERT INTO '+ TABLENAME +' (END_LOGRADOURO, END_NUMERO, END_COMPLEMENTO,
END_CEP, END_TIPO, END_CORRESP, END_PT_REFERENCIA, '+
' END_BAIRRO, END_CIDADE, EMP_CODIGO) '+
' VALUES(:LOGRADOURO, :NUMERO, :COMPLEMENTO, :CEP, :TIPO, :CORRESP, :REFERENCIA, :BAIRRO,
:CIDADE, :EMPRESA) ';
ParamByName('LOGRADOURO').AsString := Self.Logradouro;
ParamByName('NUMERO').AsString := Self.Numero;
ParamByName('COMPLEMENTO').AsString := Self.Complemento;
ParamByName('CEP').AsString := Self.Cep;
ParamByName('TIPO').AsInteger := Self.Tipo;
ParamByName('CORRESP').AsBoolean := Self.Correspondencia;
ParamByName('REFERENCIA').AsString := Self.Referencia;
ParamByName('BAIRRO').AsString := Self.Bairro;
ParamByName('CIDADE').AsString := Self.Cidade;
if Tipo = 'EMPRESA' then
ParamByName('EMPRESA').AsString := Id;
ExecSQL;
end;
Result := True;
Except
on E : Exception do
ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message);
end;
end;
function TEndereco.Merge: Boolean;
begin
// nada implementado aqui, INSERT e UPDATE executados diretamente
Result := True;
end;
procedure TEndereco.setBairro(const Value: String);
begin
_bairro := Trim(Value);
end;
procedure TEndereco.setCEP(const Value: String);
begin
_cep := Trim(Value);
end;
procedure TEndereco.setCidade(const Value: String);
begin
_cidade := Trim(Value);
end;
procedure TEndereco.setCodigo(const Value: String);
begin
_codigo := Value;
end;
procedure TEndereco.setComplemento(const Value: String);
begin
_complemento := Trim(Value);
end;
procedure TEndereco.setCorrespondencia(const Value: Boolean);
begin
_correspondencia := Value;
end;
procedure TEndereco.setLogradouro(const Value: String);
begin
_logradouro := Trim(Value);
end;
procedure TEndereco.setNumero(const Value: String);
begin
_numero := Trim(Value);
end;
procedure TEndereco.setReferencia(const Value: String);
begin
_referencia := Trim(Value);
end;
procedure TEndereco.setTipo(const Value: Integer);
begin
_tipo := Value;
end;
function TEndereco.Update(Id: String): Boolean;
begin
Try
Result := False;
with Conexao.QryCRUD do begin
Close;
SQL.Clear;
SQL.Text := 'UPDATE '+ TABLENAME +' SET END_LOGRADOURO =:LOGRADOURO, END_NUMERO =:NUMERO, '+
' END_COMPLEMENTO =:COMPLEMENTO, END_CEP =:CEP, END_TIPO =:TIPO, END_CORRESP =:CORRESP,
'+
' END_PT_REFERENCIA =:REFERENCIA, END_BAIRRO =:BAIRRO, END_CIDADE =:CIDADE '+
' WHERE END_CODIGO =:CODIGO';
ParamByName('LOGRADOURO').AsString := Self.Logradouro;
ParamByName('NUMERO').AsString := Self.Numero;
ParamByName('COMPLEMENTO').AsString := Self.Complemento;
ParamByName('BAIRRO').AsString := Self.Bairro.Codigo;
ParamByName('CIDADE').AsString := Self.Cidade.Codigo;
ParamByName('CEP').AsString := Self.Cep;
ParamByName('REFERENCIA').AsString := Self.Referencia;
ParamByName('TIPO').AsInteger := Self.Tipo;
ParamByName('CORRESP').AsBoolean := Self.Correspondencia;
ParamByName('CODIGO').AsString := Self.Codigo;
ExecSQL;
end;
Result := True;
Except
on E : Exception do
ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message);
end;
end;
function TEndereco.Validar: boolean;
begin
Result := True;
end;
end.
Prestem atenção, implementamos nossa classe TEndereco conforme o diagrama de classes da
figura 1, assim será feito com as outras classe de nosso domínio. A unit acima utiliza-se de
componentes de acesso a dados presentes em um DataModule, que fornece meios para
efetuar operações CRUD sobre o SGBD. Então vamos criar um módulo de acesso a dados
conforme abaixo:
1) Adicione um novo DataModule ao projeto através do Menu File – New – DataModule.
2) Salve a unit do DataModule como dmConexao.pas, e defina a propriedade Name do mesmo
como sendo Conexao.
3) Adicione os seguintes componentes da paleta ZeosAccess:
1 TZConnection (ZConnection): Realiza a conexão com o banco de dados;
Propriedades
Connected: false
Database: ActiveDelphi [nome do banco]
Hostname: localhost [endereço do servidor do banco]
Password: [password do usuário do banco]
Port: 5432 (default)
Protocol: postgresql-7
User: [nome do usuário do banco]
3 TZQuery (QryCRUD, QryGetObject, QryGeral): Executam comando SQL;
Propriedades
Connection: ZConnection [nome do componente de conexão]
Entre a classe Endereco e Pessoa temos uma associação de *..1, onde uma pessoa pode conter
1 ou vários endereços (residencial, comercial, de cobrança, etc). Na orientação a objetos
falamos muito sobre herança de implementação e encontramos isso no diagrama da figura 1.
Pessoa é uma classe abstrata que não pode ser instancia diretamente por um objeto, utilizada
apenas como uma classe mais genérica, ou seja, servindo como base para a definição de uma
hierarquia de classes. Sendo uma classe mais “genérica”, ela é superclasse da classe abstrata
PessoaJ que é responsável por conter dados relacionados a pessoas jurídicas. A classe Empresa
é uma classe mais especialista, é uma subclasse de PessoaJ herdando todas as suas
características, que conseqüentemente está herdando da classe Pessoa.
A organização e reutilização de código é notável neste momento, pois com a definição de
classes mais genéricas, podemos estender suas características através de classes mais
especialistas. O escopo da aplicação é o controle de estoque, abrangendo apenas o diagrama
apresentado na figura 1. Porém poderíamos desenvolver um módulo de cadastros, para
controlar fornecedores e clientes de uma empresa, por exemplo. Para isso bastaria apenas
declarar outro conjunto de classes tal qual a classe de Fornecedores e Clientes que são classes
(especialistas) pessoas do tipo Pessoa Física ou Pessoa Jurídica. Como no modelo já
adicionamos a classe PessoaJ, apenas é necessário adicionar uma classe do tipo PessoaF
(pessoa física), e uma classe Fornecedor/Cliente, do qual devem herdar todas as características
das classes Pessoa, conseqüentemente de PessoaJ ou PessoaF.
A classe abstrata Pessoa possui a responsabilidade de conter apenas a definição de atributos
comuns a todas as pessoas existentes no mundo real. Seu papel é servir apenas como base
para outra classe mais especialista. Adicione uma nova unit ao projeto através do Menu File –
New – Unit, salve a unit no diretório “classes” como clPessoa.pas. No bloco interface da unit
declare a classe conforme abaixo:
unit clPessoa;
interface
uses clEndereco;
type
TPessoa = class(TObject)
private
// métodos acessores suprimidos. getters / setters.
protected
// atributos
_telefone: String;
_fonefax: String;
_celular: String;
_email: String;
_pagina: String;
_observacao: WideString;
_status: Integer;
_endereco: TEndereco;
_dtCadastro: TDateTime;
_dtAlteracao: TDateTime;
public
// propriedades
property Telefone: String read getTelefone write setTelefone;
property FoneFax: String read getFoneFax write setFoneFax;
property Celular: String read getCelular write setCelular;
property Email: String read getEmail write setEmail;
property Pagina: String read getPagina write setPagina;
property Observacao: WideString read getObservacao write setObservacao;
property Status: Integer read getStatus write setStatus;
property Endereco: TEndereco read getEndereco write setEndereco;
property DtCadastro: TDateTime read getDtCadastro write setDtCadastro;
property DtAlteracao: TDateTime read getDtAlteracao write setDtAlteracao;
end;
implementation
// implementação suprimida, para não estender muito o artigo
end.
Encontramos no diagrama outra classe abstrata, a PessoaJ que tem como responsabilidade a
definição de atributos comuns ao tipo jurídico de pessoas (empresas que possuem a inscrição
CNPJ). A implementação de PessoaJ herda todas as características da superclasse Pessoa.
Adicione uma nova unit ao projeto através do Menu File – New – Unit, salve a unit no diretório
“classes” como clPessoaJ.pas. No bloco interface da unit declare a classe conforme abaixo:
unit clPessoaJ;
interface
uses clPessoa;
type
TPessoaJ = class(TPessoa) // classe herda de TPessoa
private
// métodos acessores suprimidos. getters / setters.
protected
_razao: String;
_fantasia: String;
_cnpj: String;
_ie: String;
_iest: String;
_im: String;
_cnae: String;
_crt: Integer;
_alias: String;
_dtAbertura: TDateTime;
_contato: String;
public
// propriedades
property Razao: String read getRazao write setRazao;
property Fantasia: String read getFantasia write setFantasia;
property CNPJ: String read getCNPJ write setCNPJ;
property IE: String read getIE write setIE;
property IEST: String read getIEST write setIEST;
property IM: String read getIM write setIM;
property Cnae: String read getCnae write setCnae;
property Crt: Integer read getCrt write setCrt;
property Alias: String read getAlias write setAlias;
property DtAbertura: TDateTime read getDtAbertura write setDtAbertura;
property Contato: String read getContato write setContato;
end;
implementation
// implementação suprimida, para não estender muito o artigo
end.
Observamos que há uma hierarquia de classes, onde temos na base uma classe mais
“genérica” e no final uma classe mais “especialista”. A classe concreta Empresa pode ser
instanciada diretamente, responsável pela definição de atributos comuns a todas as empresas
do mundo real. Em sua implementação notamos que esta classe possui apenas um atributo
(codigo), pois o restante foi herdado através da hierarquia de classes citada anteriormente.
Adicione uma nova unit ao projeto através do Menu File – New – Unit, salve a unit no diretório
“classes” como clEmpresa.pas. Nesta unit declaramos a classe conforme abaixo:
unit clEmpresa;
interface
uses clPessoaJ, clEndereco;
type
TEmpresa = class(TPessoaJ)
private
// métodos privados
// métodos acessores suprimidos. getters / setters.
function Insert(): Boolean;
function Update(): Boolean;
protected
_codigo: String;
public
constructor Create;
property Codigo: String read getCodigo write setCodigo;
// métodos publicos
function Validar(): Boolean;
function Merge(): Boolean;
function Delete(): Boolean;
function getObject(Id: String): Boolean;
procedure getMaxId;
end;
const
TABLENAME = 'EMPRESA';
implementation
// implementação suprimida, para não estender muito o artigo
end.
Agora que temos uma parte do diagrama de classes implementado no Object Pascal, vamos
construir o formulário que irá persistir os objetos do tipo Empresa. Não será especificado aqui
todos os componentes visuais e suas respectivas propriedades, tomemos como base para a
construção de nosso formulário o layout da figura 3.
Figura 3 – Formulário de cadastro de grupo de empresas.
Com o formulário criado, basta apenas adicionar os eventos necessários para inserir, editar,
visualizar e deletar registros de uma empresa, vamos criar o banco de dados a ser utilizado
neste exemplo. Como adotamos o SGBD PostgreSQL podemos utilizar a ferramenta gráfica
pgAdminIII (compõe o instalador do banco) para a criação do banco de dados e das tabelas
onde os objetos da aplicação serão persistidos.
Execute a ferramenta pgAdminIII, com ela aberta dê dois cliques no hostname onde será
criado o banco de dados, realize o login, forneça apenas a senha que foi definida ao usuário do
banco na instalação do mesmo. Com o botão direito do mouse clique em Banco de Dados –
Novo Banco de Dados. Será exibida uma caixa de diálogo, preencha conforme exibido na figura
4, e clique no botão OK para confirmar a criação da base de dados chamada “ActiveDelphi”.
Agora falta criar as tabelas onde os objetos serão persistidos, ou seja, serializados. Através do
editor SQL (clicando no ícone SQL) execute os seguintes comandos SQL DDL (Data Definition
Language):
Nota: Caso não retorne nenhum erro, os comandos SQL foram executados com sucesso no
PostgreSQL.
-- EMPRESA
CREATE TABLE EMPRESA(
EMP_CODIGO SERIAL NOT NULL,
EMP_RAZAO VARCHAR(50),
EMP_FANTASIA VARCHAR(50),
EMP_DT_CADASTRO DATE,
EMP_DT_ABERTURA DATE,
EMP_STATUS INTEGER,
EMP_ALIAS VARCHAR(50),
EMP_TELEFONE VARCHAR(14),
EMP_FONEFAX VARCHAR(14),
EMP_CNPJ VARCHAR(20),
EMP_IE VARCHAR(20),
EMP_IEST VARCHAR(20),
EMP_IM VARCHAR(20),
EMP_CRT INTEGER,
EMP_CNAE VARCHAR(10),
EMP_EMAIL VARCHAR(50),
EMP_PAGINA VARCHAR(50),
EMP_CONTATO VARCHAR(50),
EMP_MENSAGEM TEXT
);
ALTER TABLE EMPRESA ADD CONSTRAINT PK_EMPRESA PRIMARY KEY(EMP_CODIGO);
-- ENDERECO
CREATE TABLE ENDERECO(
END_CODIGO SERIAL NOT NULL,
END_LOGRADOURO VARCHAR(100) NOT NULL,
END_NUMERO VARCHAR(10) NOT NULL,
END_COMPLEMENTO VARCHAR(50),
END_CEP VARCHAR(10),
END_TIPO INTEGER,
END_CORRESP BOOLEAN,
END_PT_REFERENCIA VARCHAR(200),
END_BAIRRO VARCHAR(100),
END_CIDADE VARCHAR(100)
);
ALTER TABLE ENDERECO ADD CONSTRAINT PK_ENDERECO PRIMARY KEY(END_CODIGO);
ALTER TABLE ENDERECO ADD COLUMN EMP_CODIGO INTEGER;
ALTER TABLE ENDERECO ADD CONSTRAINT FK_END_EMPRESA FOREIGN KEY(EMP_CODIGO)
REFERENCES EMPRESA(EMP_CODIGO);
Figura 4 – Criação do banco de dados ‘ActiveDelphi’ utilizando o pgAdminIII
No formulário da figura 3, podemos utilizar a classe Empresa declarando uma variável do tipo
TEmpresa no bloco Interface/var da unit. Sendo assim, todos os dados que forem digitados no
formulário serão passados a este objeto instanciado, posteriormente persistido no SGBD. Fica
claro que os formulários presentes neste projeto apenas são projetados para a entrada e saída
de dados (visualização), pois a regra de negócios e processamento de dados fica sob a
responsabilidade da classe implementada dentro do “pacote classes”. Não estamos
trabalhando com o padrão de projeto MVC (Model-View-Controller), pois na aplicação
exemplo não implementamos o Controller, que controla a interação entre a camada View e
Model. Resumidamente trabalharemos diretamente com a View (interface gráfica) e o Model
(modelo de negócio, classes). Veja abaixo como declarar uma variável Empresa do tipo
TEmpresa definida na aplicação:
unit untCadastroEmpresa;
interface
// declaração uses e classe do formulário suprimidas
var
Empresa: TEmpresa;
No evento onShow do formulário poderíamos instanciar o objeto Empresa declarado em var,
conforme abaixo:
procedure TFrmCadastroEmpresa.FormShow(Sender: TObject);
begin
Empresa := TEmpresa.Create;
// restante do código suprimido
end;
Para simplificar este artigo, não será exibido o código-fonte dos eventos do formulário
apresentado na figura 3, porém nossa aplicação de controle de estoque implementada até
agora pode ser baixada em
http://ryanpadilha.com.br/downloads/active_delphi/controle_estoque_parte1.rar.
Todos os eventos de botões, validação de dados, instanciação/recuperação de objetos do tipo
Empresa, chamada de métodos de objetos, estão presentes no arquivo disponibilizado para
download.
Esta aplicação utiliza componentes TEdit que não possuem vínculo direto com um DataSet em
particular, ou seja, com acesso direto ao banco de dados tal como os componentes do estilo
TDBEdit. Então você está livre para alterá-lo conforme a sua necessidade e vontade.
3. Conclusão
O paradigma orientado a objetos, exposto aqui na prática, através da construção da primeira
parte de uma aplicação de controle de estoque básica, permite claramente uma maior
organização de código, ou seja, as alterações futuras serão realizadas de forma fácil, pois
temos uma clara visão sobre as responsabilidades de cada classe e suas interações. A
manutenção (alteração) de projetos de software é um processo custoso, doloroso e na maioria
das vezes produz um produto de baixa qualidade, pois as modificações podem não ser
testadas adequadamente, resultando em re-trabalho pela equipe de desenvolvimento. A parte
prática complementa o que vimos na teoria através do primeiro artigo, que expos uma série de
vantagens em relação a obtenção de qualidade em projetos de software.
Esta segunda parte propôs a modelagem do domínio de uma aplicação através da notação
UML, que oferece uma documentação padronizada e simplificada do projeto de software.
Adotando o diagrama de classes, implementamos classes no Delphi, relembrando os conceitos
abordados no primeiro artigo, porém com um foco maior na implementação das classes e sua
interação com outras classes. No terceiro e último artigo, será exposto como trabalhar com
objetos de tipos definidos (classes) em um formulário, exibindo a forma como o objeto opera
com os campos do formulário e como o mesmo pode ser chamado por outro formulário.
Caso tenha alguma dúvida entre em contato comigo. Será um prazer ajudar.
Até a terceira e última parte da série sobre a orientação a objetos. Forte Abraço!

Más contenido relacionado

La actualidad más candente

ASP.NET Web API
ASP.NET Web APIASP.NET Web API
ASP.NET Web APIhabib_786
 
Padrão de Projetos singleton
Padrão de Projetos singletonPadrão de Projetos singleton
Padrão de Projetos singletonWendel Moreira
 
Introdução FireDAC Acesso multi-banco para Delphi e C++ Builder
Introdução FireDACAcesso multi-banco para Delphi e C++ BuilderIntrodução FireDACAcesso multi-banco para Delphi e C++ Builder
Introdução FireDAC Acesso multi-banco para Delphi e C++ BuilderDiego Rosa
 
What’s new in grails framework 5?
What’s new in grails framework 5?What’s new in grails framework 5?
What’s new in grails framework 5?Puneet Behl
 
Curso : Introdução Orientação a Objetos
Curso : Introdução Orientação a ObjetosCurso : Introdução Orientação a Objetos
Curso : Introdução Orientação a Objetosdanielrpgj30
 
Nodejs - A performance que eu sempre quis ter
Nodejs - A performance que eu sempre quis terNodejs - A performance que eu sempre quis ter
Nodejs - A performance que eu sempre quis terEmerson Macedo
 
Agentes Moveis - Aspectos De Desenvolvimento
Agentes Moveis - Aspectos De  DesenvolvimentoAgentes Moveis - Aspectos De  Desenvolvimento
Agentes Moveis - Aspectos De DesenvolvimentoLuiz Matos
 
PL/SQL Interview Questions
PL/SQL Interview QuestionsPL/SQL Interview Questions
PL/SQL Interview QuestionsSrinimf-Slides
 
A la découverte de vue.js
A la découverte de vue.jsA la découverte de vue.js
A la découverte de vue.jsBruno Bonnin
 
NestJS - O framework progressivo
NestJS - O framework progressivoNestJS - O framework progressivo
NestJS - O framework progressivoWender Machado
 

La actualidad más candente (20)

ASP.NET Web API
ASP.NET Web APIASP.NET Web API
ASP.NET Web API
 
Bootstrap ppt
Bootstrap pptBootstrap ppt
Bootstrap ppt
 
Padrão de Projetos singleton
Padrão de Projetos singletonPadrão de Projetos singleton
Padrão de Projetos singleton
 
Oo delphi
Oo delphiOo delphi
Oo delphi
 
Introdução FireDAC Acesso multi-banco para Delphi e C++ Builder
Introdução FireDACAcesso multi-banco para Delphi e C++ BuilderIntrodução FireDACAcesso multi-banco para Delphi e C++ Builder
Introdução FireDAC Acesso multi-banco para Delphi e C++ Builder
 
What’s new in grails framework 5?
What’s new in grails framework 5?What’s new in grails framework 5?
What’s new in grails framework 5?
 
Oops concepts
Oops conceptsOops concepts
Oops concepts
 
JAVA - Orientação a Objetos
JAVA - Orientação a ObjetosJAVA - Orientação a Objetos
JAVA - Orientação a Objetos
 
Curso : Introdução Orientação a Objetos
Curso : Introdução Orientação a ObjetosCurso : Introdução Orientação a Objetos
Curso : Introdução Orientação a Objetos
 
Android MVVM
Android MVVMAndroid MVVM
Android MVVM
 
03 mer2
03 mer203 mer2
03 mer2
 
Nodejs - A performance que eu sempre quis ter
Nodejs - A performance que eu sempre quis terNodejs - A performance que eu sempre quis ter
Nodejs - A performance que eu sempre quis ter
 
Html5
Html5 Html5
Html5
 
Agentes Moveis - Aspectos De Desenvolvimento
Agentes Moveis - Aspectos De  DesenvolvimentoAgentes Moveis - Aspectos De  Desenvolvimento
Agentes Moveis - Aspectos De Desenvolvimento
 
PL/SQL Interview Questions
PL/SQL Interview QuestionsPL/SQL Interview Questions
PL/SQL Interview Questions
 
A la découverte de vue.js
A la découverte de vue.jsA la découverte de vue.js
A la découverte de vue.js
 
Html
HtmlHtml
Html
 
Design patterns in PHP
Design patterns in PHPDesign patterns in PHP
Design patterns in PHP
 
Spring boot
Spring bootSpring boot
Spring boot
 
NestJS - O framework progressivo
NestJS - O framework progressivoNestJS - O framework progressivo
NestJS - O framework progressivo
 

Destacado

9º FireBird Developer Day - Automatizar Manutenção do Banco de Dados
9º FireBird Developer Day - Automatizar Manutenção do Banco de Dados9º FireBird Developer Day - Automatizar Manutenção do Banco de Dados
9º FireBird Developer Day - Automatizar Manutenção do Banco de DadosJosé Araújo
 
Design Pattern MVC – Arquitetura de Software Coesa e Flexível
Design Pattern MVC – Arquitetura de Software Coesa e FlexívelDesign Pattern MVC – Arquitetura de Software Coesa e Flexível
Design Pattern MVC – Arquitetura de Software Coesa e FlexívelRyan Padilha
 
Curso De Programação Em DelPhi
Curso De Programação Em DelPhiCurso De Programação Em DelPhi
Curso De Programação Em DelPhiMikeNandes
 
Projeto de Sistemas - Aula005
Projeto de Sistemas - Aula005Projeto de Sistemas - Aula005
Projeto de Sistemas - Aula005Cláudio Amaral
 
Sistema Operacional - Pratica002
Sistema Operacional - Pratica002Sistema Operacional - Pratica002
Sistema Operacional - Pratica002Cláudio Amaral
 
Sistema Operacional - Pratica003
Sistema Operacional - Pratica003Sistema Operacional - Pratica003
Sistema Operacional - Pratica003Cláudio Amaral
 
Apostila delphi rad studio 2007
Apostila delphi   rad studio 2007Apostila delphi   rad studio 2007
Apostila delphi rad studio 2007Guilherme Bruno
 
Banco de Dados II - Unimep/Pronatec - Aula 4
Banco de Dados II - Unimep/Pronatec - Aula 4Banco de Dados II - Unimep/Pronatec - Aula 4
Banco de Dados II - Unimep/Pronatec - Aula 4André Phillip Bertoletti
 
Banco de Dados II - Aula1
Banco de Dados II - Aula1Banco de Dados II - Aula1
Banco de Dados II - Aula1Cláudio Amaral
 
Sistema Operacional - Pratica001
Sistema Operacional - Pratica001Sistema Operacional - Pratica001
Sistema Operacional - Pratica001Cláudio Amaral
 
Projeto de Sistemas - Aula004
Projeto de Sistemas - Aula004Projeto de Sistemas - Aula004
Projeto de Sistemas - Aula004Cláudio Amaral
 
Delphi Conference 2012 - Qualidade no Código
Delphi Conference 2012 - Qualidade no CódigoDelphi Conference 2012 - Qualidade no Código
Delphi Conference 2012 - Qualidade no CódigoJosé Araújo
 

Destacado (20)

Git & Delphi
Git & DelphiGit & Delphi
Git & Delphi
 
Linguagem Delphi-Introdução
Linguagem Delphi-IntroduçãoLinguagem Delphi-Introdução
Linguagem Delphi-Introdução
 
9º FireBird Developer Day - Automatizar Manutenção do Banco de Dados
9º FireBird Developer Day - Automatizar Manutenção do Banco de Dados9º FireBird Developer Day - Automatizar Manutenção do Banco de Dados
9º FireBird Developer Day - Automatizar Manutenção do Banco de Dados
 
Delphi XE7 - O que há de novo?
Delphi XE7 - O que há de novo?Delphi XE7 - O que há de novo?
Delphi XE7 - O que há de novo?
 
Design Pattern MVC – Arquitetura de Software Coesa e Flexível
Design Pattern MVC – Arquitetura de Software Coesa e FlexívelDesign Pattern MVC – Arquitetura de Software Coesa e Flexível
Design Pattern MVC – Arquitetura de Software Coesa e Flexível
 
Curso De Programação Em DelPhi
Curso De Programação Em DelPhiCurso De Programação Em DelPhi
Curso De Programação Em DelPhi
 
Apresentação fb
Apresentação fbApresentação fb
Apresentação fb
 
Firebird
FirebirdFirebird
Firebird
 
Projeto de Sistemas - Aula005
Projeto de Sistemas - Aula005Projeto de Sistemas - Aula005
Projeto de Sistemas - Aula005
 
Sistema Operacional - Pratica002
Sistema Operacional - Pratica002Sistema Operacional - Pratica002
Sistema Operacional - Pratica002
 
Sistema Operacional - Pratica003
Sistema Operacional - Pratica003Sistema Operacional - Pratica003
Sistema Operacional - Pratica003
 
Aplicativo aula006
Aplicativo aula006Aplicativo aula006
Aplicativo aula006
 
Programação aula003
Programação aula003Programação aula003
Programação aula003
 
Programação-Aula004
Programação-Aula004Programação-Aula004
Programação-Aula004
 
Apostila delphi rad studio 2007
Apostila delphi   rad studio 2007Apostila delphi   rad studio 2007
Apostila delphi rad studio 2007
 
Banco de Dados II - Unimep/Pronatec - Aula 4
Banco de Dados II - Unimep/Pronatec - Aula 4Banco de Dados II - Unimep/Pronatec - Aula 4
Banco de Dados II - Unimep/Pronatec - Aula 4
 
Banco de Dados II - Aula1
Banco de Dados II - Aula1Banco de Dados II - Aula1
Banco de Dados II - Aula1
 
Sistema Operacional - Pratica001
Sistema Operacional - Pratica001Sistema Operacional - Pratica001
Sistema Operacional - Pratica001
 
Projeto de Sistemas - Aula004
Projeto de Sistemas - Aula004Projeto de Sistemas - Aula004
Projeto de Sistemas - Aula004
 
Delphi Conference 2012 - Qualidade no Código
Delphi Conference 2012 - Qualidade no CódigoDelphi Conference 2012 - Qualidade no Código
Delphi Conference 2012 - Qualidade no Código
 

Similar a Orientação a Objetos no Delphi: Controle de Estoque

CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
CURSO DELPHI FUND. CLIENT SERVER (DIURNO) CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
CURSO DELPHI FUND. CLIENT SERVER (DIURNO) Grupo Treinar
 
hibernate annotation
hibernate annotationhibernate annotation
hibernate annotationeduardo dias
 
Banco de Dados Orientado a Objeto
Banco de Dados Orientado a ObjetoBanco de Dados Orientado a Objeto
Banco de Dados Orientado a Objetoelliando dias
 
Reutilização
ReutilizaçãoReutilização
Reutilizaçãoemjorge
 
Programação Web com Zend Framework e Ajax com Dojo
Programação Web com Zend Framework e Ajax com DojoProgramação Web com Zend Framework e Ajax com Dojo
Programação Web com Zend Framework e Ajax com Dojofabioginzel
 
Módulo 9 - Introdução à Programação Orientada a Objectos
Módulo 9 - Introdução à Programação Orientada a Objectos Módulo 9 - Introdução à Programação Orientada a Objectos
Módulo 9 - Introdução à Programação Orientada a Objectos Luis Ferreira
 
programacao-c-banco-de-dados
programacao-c-banco-de-dadosprogramacao-c-banco-de-dados
programacao-c-banco-de-dadosRaul Dias
 
Modelagem de sistemas
Modelagem de sistemasModelagem de sistemas
Modelagem de sistemassauloroos01
 
Desenvolvimento de Módulos Divi Builder
Desenvolvimento de Módulos Divi BuilderDesenvolvimento de Módulos Divi Builder
Desenvolvimento de Módulos Divi BuilderDaniel Paz
 
Conceitos de Orientação A Objeto
Conceitos de Orientação A ObjetoConceitos de Orientação A Objeto
Conceitos de Orientação A ObjetoLuciano Almeida
 
Desenvolvimento de Apps e Games para Android - Parte 5
Desenvolvimento de Apps e Games para Android - Parte 5Desenvolvimento de Apps e Games para Android - Parte 5
Desenvolvimento de Apps e Games para Android - Parte 5Erisvaldo Junior
 
Desenvolvendo aplicações com Angular e Laravel no Back-end
Desenvolvendo aplicações com Angular e Laravel no Back-endDesenvolvendo aplicações com Angular e Laravel no Back-end
Desenvolvendo aplicações com Angular e Laravel no Back-endGiovanny Valente
 

Similar a Orientação a Objetos no Delphi: Controle de Estoque (20)

CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
CURSO DELPHI FUND. CLIENT SERVER (DIURNO) CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
 
hibernate annotation
hibernate annotationhibernate annotation
hibernate annotation
 
Banco de dados_orientado_a_objetos
Banco de dados_orientado_a_objetosBanco de dados_orientado_a_objetos
Banco de dados_orientado_a_objetos
 
Oficina cake php
Oficina cake phpOficina cake php
Oficina cake php
 
Banco de Dados Orientado a Objeto
Banco de Dados Orientado a ObjetoBanco de Dados Orientado a Objeto
Banco de Dados Orientado a Objeto
 
Modelo de desenvolvimento de software em 3 camadas para Wordpress
Modelo de desenvolvimento de software em 3 camadas para WordpressModelo de desenvolvimento de software em 3 camadas para Wordpress
Modelo de desenvolvimento de software em 3 camadas para Wordpress
 
Reutilização
ReutilizaçãoReutilização
Reutilização
 
Programação Web com Zend Framework e Ajax com Dojo
Programação Web com Zend Framework e Ajax com DojoProgramação Web com Zend Framework e Ajax com Dojo
Programação Web com Zend Framework e Ajax com Dojo
 
Módulo 9 - Introdução à Programação Orientada a Objectos
Módulo 9 - Introdução à Programação Orientada a Objectos Módulo 9 - Introdução à Programação Orientada a Objectos
Módulo 9 - Introdução à Programação Orientada a Objectos
 
Java7
Java7Java7
Java7
 
programacao-c-banco-de-dados
programacao-c-banco-de-dadosprogramacao-c-banco-de-dados
programacao-c-banco-de-dados
 
Palestra
PalestraPalestra
Palestra
 
Modelagem de sistemas
Modelagem de sistemasModelagem de sistemas
Modelagem de sistemas
 
Data accesss conect
Data accesss conectData accesss conect
Data accesss conect
 
Dao
DaoDao
Dao
 
Desenvolvimento de Módulos Divi Builder
Desenvolvimento de Módulos Divi BuilderDesenvolvimento de Módulos Divi Builder
Desenvolvimento de Módulos Divi Builder
 
Aula1
Aula1Aula1
Aula1
 
Conceitos de Orientação A Objeto
Conceitos de Orientação A ObjetoConceitos de Orientação A Objeto
Conceitos de Orientação A Objeto
 
Desenvolvimento de Apps e Games para Android - Parte 5
Desenvolvimento de Apps e Games para Android - Parte 5Desenvolvimento de Apps e Games para Android - Parte 5
Desenvolvimento de Apps e Games para Android - Parte 5
 
Desenvolvendo aplicações com Angular e Laravel no Back-end
Desenvolvendo aplicações com Angular e Laravel no Back-endDesenvolvendo aplicações com Angular e Laravel no Back-end
Desenvolvendo aplicações com Angular e Laravel no Back-end
 

Más de Ryan Padilha

Percepções de uma viagem em dois mundos: Java e Python
Percepções de uma viagem em dois mundos:  Java e PythonPercepções de uma viagem em dois mundos:  Java e Python
Percepções de uma viagem em dois mundos: Java e PythonRyan Padilha
 
Microservices - Arquitetura, Ecossistema e Desafios
Microservices - Arquitetura, Ecossistema e DesafiosMicroservices - Arquitetura, Ecossistema e Desafios
Microservices - Arquitetura, Ecossistema e DesafiosRyan Padilha
 
Arquitetura monolítica à orientação a serviços
Arquitetura monolítica à orientação a serviçosArquitetura monolítica à orientação a serviços
Arquitetura monolítica à orientação a serviçosRyan Padilha
 
Startups - O novo paradigma da administração
Startups - O novo paradigma da administraçãoStartups - O novo paradigma da administração
Startups - O novo paradigma da administraçãoRyan Padilha
 
Flask e Docker - rumo a AWS!
Flask e Docker - rumo a AWS!Flask e Docker - rumo a AWS!
Flask e Docker - rumo a AWS!Ryan Padilha
 
Python em Ambientes Distribuídos - Arquitetura Moderna
Python em Ambientes Distribuídos - Arquitetura ModernaPython em Ambientes Distribuídos - Arquitetura Moderna
Python em Ambientes Distribuídos - Arquitetura ModernaRyan Padilha
 
Plataforma Android: Produtividade Além do SDK
Plataforma Android: Produtividade Além do SDKPlataforma Android: Produtividade Além do SDK
Plataforma Android: Produtividade Além do SDKRyan Padilha
 

Más de Ryan Padilha (7)

Percepções de uma viagem em dois mundos: Java e Python
Percepções de uma viagem em dois mundos:  Java e PythonPercepções de uma viagem em dois mundos:  Java e Python
Percepções de uma viagem em dois mundos: Java e Python
 
Microservices - Arquitetura, Ecossistema e Desafios
Microservices - Arquitetura, Ecossistema e DesafiosMicroservices - Arquitetura, Ecossistema e Desafios
Microservices - Arquitetura, Ecossistema e Desafios
 
Arquitetura monolítica à orientação a serviços
Arquitetura monolítica à orientação a serviçosArquitetura monolítica à orientação a serviços
Arquitetura monolítica à orientação a serviços
 
Startups - O novo paradigma da administração
Startups - O novo paradigma da administraçãoStartups - O novo paradigma da administração
Startups - O novo paradigma da administração
 
Flask e Docker - rumo a AWS!
Flask e Docker - rumo a AWS!Flask e Docker - rumo a AWS!
Flask e Docker - rumo a AWS!
 
Python em Ambientes Distribuídos - Arquitetura Moderna
Python em Ambientes Distribuídos - Arquitetura ModernaPython em Ambientes Distribuídos - Arquitetura Moderna
Python em Ambientes Distribuídos - Arquitetura Moderna
 
Plataforma Android: Produtividade Além do SDK
Plataforma Android: Produtividade Além do SDKPlataforma Android: Produtividade Além do SDK
Plataforma Android: Produtividade Além do SDK
 

Orientação a Objetos no Delphi: Controle de Estoque

  • 1. Orientação a Objetos no Delphi: Controle de Estoque – Parte II Ryan Bruno C Padilha ryan.padilha@gmail.com http://ryanpadilha.com.br Objetivo deste artigo Este artigo é o segundo de uma série de três artigos onde abordamos o paradigma orientado a objetos. No primeiro artigo foi introduzido os principais conceitos da orientação a objetos, sempre comparando a OO com o modelo de programação estrutural, permitindo assim ao leitor uma maior reflexão sobre o que seria interessante utilizar em projetos de software. Nesta segunda parte iniciaremos a construção de uma aplicação de controle de estoque básico, empregando todos os conceitos anteriormente abordados, provando na prática que a OO é viável, e até mesmo recomendada para projetos de média e grande complexidade. Utilizaremos este exemplo prático como referência, ou seja, uma orientação para o desenvolvimento de futuras aplicações, que poderão empregar todos os recursos que a orientação a objetos nos proporciona. 1. Descrição do Modelo Conceitual Ao iniciar um projeto de software abordando o paradigma orientado a objetos, seria interessante começarmos o processo de desenvolvimento através da modelagem das classes de negócios, identificando os elementos que fazem parte da aplicação. A modelagem pode ser realizada através da notação UML (Unified Modeling Language), que oferece um modelo de diagrama ideal para modelagem de classes – o diagrama de classe - do qual irá conter toda a lógica de interações entre os objetos que compõe o escopo do projeto. Nesta série sobre OO somente será adotado o diagrama de classes, considerado “a espinha dorsal” da UML e amplamente difundido entre os desenvolvedores, de fácil entendimento e utilização. Conforme citado no primeiro artigo, uma boa ferramenta para realizarmos a modelagem de classes, é o software Judy Community, que pode ser encontrado em http://jude.change- vision.com/jude-web/product/community.html. Existem outros diagramas na UML que poderiam ser adotados na modelagem da aplicação. São separados por categorias: 1) Diagramas Estruturais de: objeto, componentes, instalação, pacote, estrutura e classe; 2) Diagramas Comportamentais de: caso de uso, estado e atividade; 3) Diagrama de Interação (comportamentais) de: seqüência, interatividade, colaboração e sincronização. Muitos desenvolvedores neste momento podem se perguntar: o que é um controle de estoque? O controle de estoque tem como objetivo otimizar o investimento em estoques, aumentar o uso eficiente dos meios internos de uma empresa e minimizar as necessidades de capital investido em estoque. É uma área fundamental da empresa, pois através dela somos capazes de prever o quanto será necessário comprar de um determinado produto, além de outras informações úteis sobre as vendas, e a movimentação de entrada / saída de produtos do estoque. Os elementos básicos de uma aplicação de controle de estoque estão relacionados abaixo.
  • 2. Trabalharemos com o domínio de uma aplicação voltada para o controle de estoque de produtos representado pela figura 1, que possui as seguintes classes: Endereco, Pessoa (classe abstrata), PessoaJ (classe abstrata), Empesa, Estoque, Pedido, Entrada, Produto, Marca, Unidade e Categoria. Observamos a presença da declaração de atributos e métodos em cada classe – os atributos possuem o modificador de visibilidade private, reforçando o conceito de encapsulamento de atributos, através de métodos acessores do tipo getter e setter (retornando e atribuindo valores, respectivamente), alterando o estado do objeto instanciado. Os métodos acessores são utilizados na declaração Property (propriedade), sobrecarregando as operações de leitura (read) e escrita (write) executadas quando a propriedade for acessada. A declaração citada desempenha papel fundamental ao proteger o acesso ao objeto, definindo uma forma padronizada de acesso ao estado do objeto (as propriedades e métodos getters/setters foram omitidos do diagrama de classes apresentado na figura 1) . O atributo TABLENAME é estático, cada classe concreta poderá (em nosso diagrama deve) possuir um determinado nome de tabela, que deverá ser mapeado para uma tabela no modelo de banco de dados objeto-relacional. Além dos métodos acessores sobrecarregados por Property, é declarado e implementado um conjunto de métodos que realizam operações sobre o SGBD (Sistema Gerenciador de Banco de Dados) executando comandos SQL/DML (Structured Query Language/Data Manipulation Language): 1) SELECT – Selecionar objetos persistidos em uma tabela, serializando as colunas em atributos de classe. Os métodos assinados como getObject(Id: String): boolean e getObjects(): boolean recuperam objetos do SGBD; 2) INSERT – Persistir objetos em uma tabela, serializando seu atributos em colunas. O método assinado como public Merge(): boolean verifica se o atributo código do objeto está com presença de valor (diferente de vazio/0), se o mesmo não contiver nenhum valor o comando INSERT será executado através da chamada do método private Insert(): boolean; 3) UPDATE – Atualizar objetos em uma tabela, que foram selecionados anteriormente (des- serializados) e estão instanciados na memória principal; empregando um filtro WHERE que dispõem de condições comparativas, neste caso usamos o identificador único do objeto, o Id (código) que é chave primária da tabela onde o objeto está sendo recuperado/persistido. O método assinado como public Merge(): boolean chamado para executar o comando INSERT é utilizado também para a execução do comando UPDATE, se o atributo código do objeto recuperado for consistente o método private Update(): boolean é invocado; 4) DELETE – Deletar objetos em uma tabela. Um objeto recuperado do SGBD e instanciado na memória principal, pode ser excluído através da chamada do método Delete(): boolean executando o comando DELETE. Usamos como referência o identificador único do objeto, o Id (código), citado anteriormente. O conjunto das quatro operações básicas relacionadas acima empregadas em SGBD objeto- relacional, reconhecido como CRUD (acrônimo de Create, Retrieve, Update, Delete) é implementado na maioria das aplicações que adotam o paradigma orientado a objetos. É notado que o CRUD contém assinaturas de métodos comuns na maioria das classes concretas em que estão implementados, e possuem comportamento semelhante - o de executar instruções SQL. Poderemos em um próximo artigo descrever a arquitetura e implementar uma biblioteca de classes que se relacionam entre si através de associações e composições, com a
  • 3. finalidade de automatizar o processo de Mapeamento Objeto-Relacional ao adotar o paradigma orientação a objetos. A tarefa de mapear objetos em entidade relacional é algo na maioria das vezes repetitivo, onde serializamos e des-serializamos objetos, ou seja, mapeando atributo-coluna / coluna-atributo em determinada tabela presente no Schema do usuário do SGBD. Figura 1 – Diagrama de classes simplificado. Domínio: Controle de Estoque. 2. Implementação em Object Pascal do diagrama de classes de domínio Este exemplo tem finalidade educacional e pode ser modificado, alterado e distribuído. Caso seja utilizado para fins didáticos por outras pessoas, preserve o nome do autor. Como exemplo para esta série de artigos, criaremos uma aplicação conforme apresentado pelo diagrama da figura 1. Adotamos a IDE Delphi 7 (mais nada impede a utilização de outras versões do Delphi), o intuito é apresentar os conceitos da orientação a objetos através de uma implementação de um software real, com a finalidade de controlar o estoque de produtos de uma empresa do ramo varejista e/ou atacadista. Para realizar a persistência de objetos, ou seja, efetuar a gravação permanente de objetos para a futura recuperação dos mesmos, e até para manter um histórico de tudo o que ocorreu até hoje com o estoque de uma empresa, é necessário a utilização de um SGBD.
  • 4. O SGBD PostgreSQL 8.3, banco de dados objeto-relacional, é adotado neste exemplo por ser open-source (não é necessário adquirir licença para utilizá-lo), de fácil instalação e manutenção, robusto, confiável, flexível, rico em recursos, dentre outras características. Oferece suporte a comandos complexos, chaves estrangeiras, gatilhos (triggers), visões, integridade transacional, e controle de simultaneidade multiversão. Pode ser encontrado em http://www.postgresql.org. Não será exibido aqui como instalar o PostgreSQL, sua instalação é simples e rápida. Caso haja alguma dúvida em como efetuar a instalação, procure informações em fóruns e websites especializados neste banco de dados. Um ponto importante que deve ser analisado com cuidado é: qual componente de acesso a dados pode ser utilizado para acessar os dados no PostgreSQL? Como muitos desenvolvedores que estão lendo este artigo trabalham com diversos ambientes de banco de dados, é interessante escolher um componente de acesso que ofereça uma maior flexibilidade e facilidade durante a utilização e/ou migração de um banco de dados para outro. Tendo isto como requisito básico de projeto, podemos utilizar a biblioteca ZeosLib que é open-source (assim como o PostgreSQL), suporta conexão nativa e transparente, composto por um conjunto de componentes de banco de dados que oferece suporte a diversos banco de dados: MySQL, PostgreSQL, Firebird, MSSQL Server, Oracle e SQLite. Para quem ainda não tem o ZeosLib instalado no Delphi, efetue o download em http://sourceforge.net/projects/zeoslib/, durante a escrita deste artigo, a versão estável disponível para download do ZeosLib era ZEOSDBO-6.6.6-stable, porém no exemplo que será desenvolvido foi utilizado a versão 6.6.2- RC. Caso tenha alguma dúvida entre as diversas versões disponíveis e a diferença entre elas, leia o File Releases do projeto ZeosLib. Sua instalação é relativamente simples, bastando seguir um passo-a-passo no estilo “receita de bolo” e pronto. Para maiores detalhes sobre a instalação veja em http://www.activedelphi.com.br/forum/viewtopic.php?t=33645. Não será exibido aqui como instalar a biblioteca ZeosLib, pois pode ser encontrado no próprio Active Delphi informações de como proceder. Figura 2 – Biblioteca ZeosLib no Delphi 7 (aba ZeosAccess). Após adquirir o SGBD PostgreSQL e o componente de acesso a dados ZeosLib instalados no ambiente de trabalho, podemos iniciar o projeto de software. Com o Delphi aberto crie um novo projeto chamado “ControleEstoque” (menu File – New – Application) e salve-o no diretório “d:projetosoocontrole_estoque” ou escolha um local de sua preferência. No formulário principal que é exibido na tela adicione o seguinte componente visual: - TMainMenu: Adicione o menu Cadastros contendo os itens: Grupo de Empresas, Produtos. Neste últimos criaremos um sub-menu contendo: Cadastro de Produto, Cadastro de Marca, Cadastro de Unidade e Cadastro de Categoria. Adicione o menu Movimentação contendo o item Movimentação de Estoque. E por último adiciona o menu Sobre. A princípio estamos modelando a apresentação visual de nossa aplicação, definindo o formulário principal e seu menu de navegação, que fornecerá acesso aos formulários da
  • 5. aplicação que serão criados posteriormente. Dentro do diretório do projeto crie um diretório “classes” – com a função de agrupar as classes de negócio implementadas no projeto; e outro diretório “view” – utilizado com repositório de formulários construídos através do designer. Os diretórios criados atuam como pacotes, armazenando código-fonte semelhantes, ou seja, todas as nossas classes estarão contidas dentro de “classes” e os formulários dentro de “view”, com isso obtemos uma maior organização. Se futuramente quisermos reaproveitar nossas classes de negócios em outro projeto, será fácil localizar e compartilhar o mesmo código-fonte com outro projeto de software que se beneficiaria da implementação realizada neste módulo de controle de estoque, promovendo a reutilização de código – característica fundamental da orientação a objetos. 2.1 Classes de negócio No projeto de software modelamos as classes de negócio, cada classe é implementada em uma unit, por exemplo a classe Endereco é definida na unit clEndereco e assim por diante. É adotado uma convenção de código, definindo um padrão para a codificação, melhorando com isso a legibilidade do código-fonte. Segue abaixo a convenção utilizada aqui: 1) clNomeUnit: define o nome da unit que contém a implementação da classe. Exemplo: clEndereco, clPessoa, clPessoaJ, clEmpresa, clEstoque, clProduto. 2) TNomeClasse: define o nome da classe. Toda classe definida no Delphi inicia com a letra T. Exemplo: TEndereco, TPessoa, TPessoaJ, TEmpresa, TEstoque, TProduto. 3) _nomeAtributo: define o nome de atributo. Exemplo: _codigo, _logradouro, _numero, _nome. 4) NomeProperty: define o nome da propriedade. A primeira letra em maiúsculo e o restante da palavra em minúsculo. Exemplo: Codigo, Logradouro, Numero, NomeComp. Comecemos com a implementação da classe concreta Endereco, a responsabilidade dessa classe é conter dados relacionado aos endereços da classe abstrata Pessoa. Adicione uma nova unit ao projeto através de Menu File – New – Unit, salve a unit no diretório “classes” como clEndereco.pas. No bloco interface/implementation da unit declare/implemente a classe conforme abaixo: unit clEndereco; interface type TEndereco = class(TObject) private // métodos acessores suprimidos. getters / setters. protected // declaração de atributos _codigo: String; _logradouro: String; _numero: String; _complemento: String; _cep: String; _tipo: Integer;
  • 6. _correspondencia: Boolean; _referencia: String; _bairro: String; _cidade: String; public // declaração das propriedades da classe, encapsulamento de atributos property Codigo: String read getCodigo write setCodigo; property Logradouro: String read getLogradouro write setLogradouro; property Numero: String read getNumero write setNumero; property Complemento: String read getComplemento write setComplemento; property Cep: String read getCEP write setCEP; property Tipo: Integer read getTipo write setTipo; property Correspondencia: Boolean read getCorrespondencia write setCorrespondencia; property Referencia: String read getReferencia write setReferencia; property Bairro: String read getBairro write setBairro; property Cidade: String read getCidade write setCidade; // nesta última linha pressione Ctrl + Shift + C // para gerar os métodos acessores getters e setters automaticamente // declaração de métodos function Validar(): boolean; function Merge(): Boolean; function Delete(Filtro: String): Boolean; function getObject(Id: String; Filtro: String): Boolean; function Insert(Id: String; Tipo: String): Boolean; function Update(Id: String): Boolean; end; const TABLENAME = 'ENDERECO'; implementation uses clUtil, SysUtils, dmConexao, DB, ZDataset, ZAbstractRODataset, Variants; { TEndereco } function TEndereco.Delete(Filtro: String): Boolean; begin try Result := False; with Conexao.QryCRUD do begin Close; SQL.Clear; SQL.Text := 'DELETE FROM '+ TABLENAME +' WHERE END_CODIGO =:CODIGO'; ParamByName('CODIGO').AsString := Self.Codigo; ExecSQL; end; Result := True; Except on E : Exception do ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message); end; end;
  • 7. function TEndereco.getBairro: String; begin Result := _bairro; end; function TEndereco.getCEP: String; begin Result := _cep; end; function TEndereco.getCidade: String; begin Result := _cidade; end; function TEndereco.getCodigo: String; begin Result := _codigo; end; function TEndereco.getComplemento: String; begin Result := _complemento; end; function TEndereco.getCorrespondencia: Boolean; begin Result := _correspondencia; end; function TEndereco.getLogradouro: String; begin Result := _logradouro; end; function TEndereco.getNumero: String; begin Result := _numero; end; function TEndereco.getObject(Id: String; Filtro: String): Boolean; begin Try Result := False; if TUtil.Empty(Id) then Exit; with Conexao.QryGetObject do begin Close; SQL.Clear; SQL.Add('SELECT * FROM '+ TABLENAME); if filtro = 'ENDERECO' then begin SQL.Add(' WHERE END_CODIGO =:CODIGO');
  • 8. ParamByName('CODIGO').AsString := Id; end else if filtro = 'EMPRESA' then begin SQL.Add(' WHERE EMP_CODIGO =:CODIGO'); ParamByName('CODIGO').AsString := Id; end; Open; First; end; if Conexao.QryGetObject.RecordCount > 0 then begin Self.Codigo := Conexao.QryGetObject.FieldByName('END_CODIGO').AsString; Self.Logradouro := Conexao.QryGetObject.FieldByName('END_LOGRADOURO').AsString; Self.Numero := Conexao.QryGetObject.FieldByName('END_NUMERO').AsString; Self.Complemento := Conexao.QryGetObject.FieldByName('END_COMPLEMENTO').AsString; Self.Bairro := Conexao.QryGetObject.FieldByName('END_BAIRRO').AsString; Self.Cidade := Conexao.QryGetObject.FieldByName('END_CIDADE').AsString; self.Cep := Conexao.QryGetObject.FieldByName('END_CEP').AsString; Self.Referencia := Conexao.QryGetObject.FieldByName('END_PT_REFERENCIA').AsString; Self.Tipo := Conexao.QryGetObject.FieldByName('END_TIPO').AsInteger; Self.Correspondencia := Conexao.QryGetObject.FieldByName('END_CORRESP').AsBoolean; Result := True; end else ShowMessage('Registro não encontrado!'); Except on E : Exception do ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message); end; end; function TEndereco.getReferencia: String; begin Result := _referencia; end; function TEndereco.getTipo: Integer; begin Result := _tipo; end; function TEndereco.Insert(Id: String; Tipo: String): Boolean; begin Try Result := False; with Conexao.QryCRUD do begin Close; SQL.Clear; SQL.Text := 'INSERT INTO '+ TABLENAME +' (END_LOGRADOURO, END_NUMERO, END_COMPLEMENTO, END_CEP, END_TIPO, END_CORRESP, END_PT_REFERENCIA, '+ ' END_BAIRRO, END_CIDADE, EMP_CODIGO) '+
  • 9. ' VALUES(:LOGRADOURO, :NUMERO, :COMPLEMENTO, :CEP, :TIPO, :CORRESP, :REFERENCIA, :BAIRRO, :CIDADE, :EMPRESA) '; ParamByName('LOGRADOURO').AsString := Self.Logradouro; ParamByName('NUMERO').AsString := Self.Numero; ParamByName('COMPLEMENTO').AsString := Self.Complemento; ParamByName('CEP').AsString := Self.Cep; ParamByName('TIPO').AsInteger := Self.Tipo; ParamByName('CORRESP').AsBoolean := Self.Correspondencia; ParamByName('REFERENCIA').AsString := Self.Referencia; ParamByName('BAIRRO').AsString := Self.Bairro; ParamByName('CIDADE').AsString := Self.Cidade; if Tipo = 'EMPRESA' then ParamByName('EMPRESA').AsString := Id; ExecSQL; end; Result := True; Except on E : Exception do ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message); end; end; function TEndereco.Merge: Boolean; begin // nada implementado aqui, INSERT e UPDATE executados diretamente Result := True; end; procedure TEndereco.setBairro(const Value: String); begin _bairro := Trim(Value); end; procedure TEndereco.setCEP(const Value: String); begin _cep := Trim(Value); end; procedure TEndereco.setCidade(const Value: String); begin _cidade := Trim(Value); end; procedure TEndereco.setCodigo(const Value: String); begin _codigo := Value; end; procedure TEndereco.setComplemento(const Value: String); begin _complemento := Trim(Value);
  • 10. end; procedure TEndereco.setCorrespondencia(const Value: Boolean); begin _correspondencia := Value; end; procedure TEndereco.setLogradouro(const Value: String); begin _logradouro := Trim(Value); end; procedure TEndereco.setNumero(const Value: String); begin _numero := Trim(Value); end; procedure TEndereco.setReferencia(const Value: String); begin _referencia := Trim(Value); end; procedure TEndereco.setTipo(const Value: Integer); begin _tipo := Value; end; function TEndereco.Update(Id: String): Boolean; begin Try Result := False; with Conexao.QryCRUD do begin Close; SQL.Clear; SQL.Text := 'UPDATE '+ TABLENAME +' SET END_LOGRADOURO =:LOGRADOURO, END_NUMERO =:NUMERO, '+ ' END_COMPLEMENTO =:COMPLEMENTO, END_CEP =:CEP, END_TIPO =:TIPO, END_CORRESP =:CORRESP, '+ ' END_PT_REFERENCIA =:REFERENCIA, END_BAIRRO =:BAIRRO, END_CIDADE =:CIDADE '+ ' WHERE END_CODIGO =:CODIGO'; ParamByName('LOGRADOURO').AsString := Self.Logradouro; ParamByName('NUMERO').AsString := Self.Numero; ParamByName('COMPLEMENTO').AsString := Self.Complemento; ParamByName('BAIRRO').AsString := Self.Bairro.Codigo; ParamByName('CIDADE').AsString := Self.Cidade.Codigo; ParamByName('CEP').AsString := Self.Cep; ParamByName('REFERENCIA').AsString := Self.Referencia; ParamByName('TIPO').AsInteger := Self.Tipo; ParamByName('CORRESP').AsBoolean := Self.Correspondencia; ParamByName('CODIGO').AsString := Self.Codigo; ExecSQL; end; Result := True;
  • 11. Except on E : Exception do ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message); end; end; function TEndereco.Validar: boolean; begin Result := True; end; end. Prestem atenção, implementamos nossa classe TEndereco conforme o diagrama de classes da figura 1, assim será feito com as outras classe de nosso domínio. A unit acima utiliza-se de componentes de acesso a dados presentes em um DataModule, que fornece meios para efetuar operações CRUD sobre o SGBD. Então vamos criar um módulo de acesso a dados conforme abaixo: 1) Adicione um novo DataModule ao projeto através do Menu File – New – DataModule. 2) Salve a unit do DataModule como dmConexao.pas, e defina a propriedade Name do mesmo como sendo Conexao. 3) Adicione os seguintes componentes da paleta ZeosAccess: 1 TZConnection (ZConnection): Realiza a conexão com o banco de dados; Propriedades Connected: false Database: ActiveDelphi [nome do banco] Hostname: localhost [endereço do servidor do banco] Password: [password do usuário do banco] Port: 5432 (default) Protocol: postgresql-7 User: [nome do usuário do banco] 3 TZQuery (QryCRUD, QryGetObject, QryGeral): Executam comando SQL; Propriedades Connection: ZConnection [nome do componente de conexão] Entre a classe Endereco e Pessoa temos uma associação de *..1, onde uma pessoa pode conter 1 ou vários endereços (residencial, comercial, de cobrança, etc). Na orientação a objetos falamos muito sobre herança de implementação e encontramos isso no diagrama da figura 1. Pessoa é uma classe abstrata que não pode ser instancia diretamente por um objeto, utilizada apenas como uma classe mais genérica, ou seja, servindo como base para a definição de uma hierarquia de classes. Sendo uma classe mais “genérica”, ela é superclasse da classe abstrata PessoaJ que é responsável por conter dados relacionados a pessoas jurídicas. A classe Empresa
  • 12. é uma classe mais especialista, é uma subclasse de PessoaJ herdando todas as suas características, que conseqüentemente está herdando da classe Pessoa. A organização e reutilização de código é notável neste momento, pois com a definição de classes mais genéricas, podemos estender suas características através de classes mais especialistas. O escopo da aplicação é o controle de estoque, abrangendo apenas o diagrama apresentado na figura 1. Porém poderíamos desenvolver um módulo de cadastros, para controlar fornecedores e clientes de uma empresa, por exemplo. Para isso bastaria apenas declarar outro conjunto de classes tal qual a classe de Fornecedores e Clientes que são classes (especialistas) pessoas do tipo Pessoa Física ou Pessoa Jurídica. Como no modelo já adicionamos a classe PessoaJ, apenas é necessário adicionar uma classe do tipo PessoaF (pessoa física), e uma classe Fornecedor/Cliente, do qual devem herdar todas as características das classes Pessoa, conseqüentemente de PessoaJ ou PessoaF. A classe abstrata Pessoa possui a responsabilidade de conter apenas a definição de atributos comuns a todas as pessoas existentes no mundo real. Seu papel é servir apenas como base para outra classe mais especialista. Adicione uma nova unit ao projeto através do Menu File – New – Unit, salve a unit no diretório “classes” como clPessoa.pas. No bloco interface da unit declare a classe conforme abaixo: unit clPessoa; interface uses clEndereco; type TPessoa = class(TObject) private // métodos acessores suprimidos. getters / setters. protected // atributos _telefone: String; _fonefax: String; _celular: String; _email: String; _pagina: String; _observacao: WideString; _status: Integer; _endereco: TEndereco; _dtCadastro: TDateTime; _dtAlteracao: TDateTime; public // propriedades property Telefone: String read getTelefone write setTelefone; property FoneFax: String read getFoneFax write setFoneFax; property Celular: String read getCelular write setCelular; property Email: String read getEmail write setEmail; property Pagina: String read getPagina write setPagina; property Observacao: WideString read getObservacao write setObservacao; property Status: Integer read getStatus write setStatus; property Endereco: TEndereco read getEndereco write setEndereco; property DtCadastro: TDateTime read getDtCadastro write setDtCadastro;
  • 13. property DtAlteracao: TDateTime read getDtAlteracao write setDtAlteracao; end; implementation // implementação suprimida, para não estender muito o artigo end. Encontramos no diagrama outra classe abstrata, a PessoaJ que tem como responsabilidade a definição de atributos comuns ao tipo jurídico de pessoas (empresas que possuem a inscrição CNPJ). A implementação de PessoaJ herda todas as características da superclasse Pessoa. Adicione uma nova unit ao projeto através do Menu File – New – Unit, salve a unit no diretório “classes” como clPessoaJ.pas. No bloco interface da unit declare a classe conforme abaixo: unit clPessoaJ; interface uses clPessoa; type TPessoaJ = class(TPessoa) // classe herda de TPessoa private // métodos acessores suprimidos. getters / setters. protected _razao: String; _fantasia: String; _cnpj: String; _ie: String; _iest: String; _im: String; _cnae: String; _crt: Integer; _alias: String; _dtAbertura: TDateTime; _contato: String; public // propriedades property Razao: String read getRazao write setRazao; property Fantasia: String read getFantasia write setFantasia; property CNPJ: String read getCNPJ write setCNPJ; property IE: String read getIE write setIE; property IEST: String read getIEST write setIEST; property IM: String read getIM write setIM; property Cnae: String read getCnae write setCnae; property Crt: Integer read getCrt write setCrt; property Alias: String read getAlias write setAlias; property DtAbertura: TDateTime read getDtAbertura write setDtAbertura; property Contato: String read getContato write setContato; end; implementation // implementação suprimida, para não estender muito o artigo end.
  • 14. Observamos que há uma hierarquia de classes, onde temos na base uma classe mais “genérica” e no final uma classe mais “especialista”. A classe concreta Empresa pode ser instanciada diretamente, responsável pela definição de atributos comuns a todas as empresas do mundo real. Em sua implementação notamos que esta classe possui apenas um atributo (codigo), pois o restante foi herdado através da hierarquia de classes citada anteriormente. Adicione uma nova unit ao projeto através do Menu File – New – Unit, salve a unit no diretório “classes” como clEmpresa.pas. Nesta unit declaramos a classe conforme abaixo: unit clEmpresa; interface uses clPessoaJ, clEndereco; type TEmpresa = class(TPessoaJ) private // métodos privados // métodos acessores suprimidos. getters / setters. function Insert(): Boolean; function Update(): Boolean; protected _codigo: String; public constructor Create; property Codigo: String read getCodigo write setCodigo; // métodos publicos function Validar(): Boolean; function Merge(): Boolean; function Delete(): Boolean; function getObject(Id: String): Boolean; procedure getMaxId; end; const TABLENAME = 'EMPRESA'; implementation // implementação suprimida, para não estender muito o artigo end. Agora que temos uma parte do diagrama de classes implementado no Object Pascal, vamos construir o formulário que irá persistir os objetos do tipo Empresa. Não será especificado aqui todos os componentes visuais e suas respectivas propriedades, tomemos como base para a construção de nosso formulário o layout da figura 3.
  • 15. Figura 3 – Formulário de cadastro de grupo de empresas. Com o formulário criado, basta apenas adicionar os eventos necessários para inserir, editar, visualizar e deletar registros de uma empresa, vamos criar o banco de dados a ser utilizado neste exemplo. Como adotamos o SGBD PostgreSQL podemos utilizar a ferramenta gráfica pgAdminIII (compõe o instalador do banco) para a criação do banco de dados e das tabelas onde os objetos da aplicação serão persistidos. Execute a ferramenta pgAdminIII, com ela aberta dê dois cliques no hostname onde será criado o banco de dados, realize o login, forneça apenas a senha que foi definida ao usuário do banco na instalação do mesmo. Com o botão direito do mouse clique em Banco de Dados – Novo Banco de Dados. Será exibida uma caixa de diálogo, preencha conforme exibido na figura 4, e clique no botão OK para confirmar a criação da base de dados chamada “ActiveDelphi”. Agora falta criar as tabelas onde os objetos serão persistidos, ou seja, serializados. Através do editor SQL (clicando no ícone SQL) execute os seguintes comandos SQL DDL (Data Definition Language): Nota: Caso não retorne nenhum erro, os comandos SQL foram executados com sucesso no PostgreSQL. -- EMPRESA CREATE TABLE EMPRESA( EMP_CODIGO SERIAL NOT NULL, EMP_RAZAO VARCHAR(50),
  • 16. EMP_FANTASIA VARCHAR(50), EMP_DT_CADASTRO DATE, EMP_DT_ABERTURA DATE, EMP_STATUS INTEGER, EMP_ALIAS VARCHAR(50), EMP_TELEFONE VARCHAR(14), EMP_FONEFAX VARCHAR(14), EMP_CNPJ VARCHAR(20), EMP_IE VARCHAR(20), EMP_IEST VARCHAR(20), EMP_IM VARCHAR(20), EMP_CRT INTEGER, EMP_CNAE VARCHAR(10), EMP_EMAIL VARCHAR(50), EMP_PAGINA VARCHAR(50), EMP_CONTATO VARCHAR(50), EMP_MENSAGEM TEXT ); ALTER TABLE EMPRESA ADD CONSTRAINT PK_EMPRESA PRIMARY KEY(EMP_CODIGO); -- ENDERECO CREATE TABLE ENDERECO( END_CODIGO SERIAL NOT NULL, END_LOGRADOURO VARCHAR(100) NOT NULL, END_NUMERO VARCHAR(10) NOT NULL, END_COMPLEMENTO VARCHAR(50), END_CEP VARCHAR(10), END_TIPO INTEGER, END_CORRESP BOOLEAN, END_PT_REFERENCIA VARCHAR(200), END_BAIRRO VARCHAR(100), END_CIDADE VARCHAR(100) ); ALTER TABLE ENDERECO ADD CONSTRAINT PK_ENDERECO PRIMARY KEY(END_CODIGO); ALTER TABLE ENDERECO ADD COLUMN EMP_CODIGO INTEGER; ALTER TABLE ENDERECO ADD CONSTRAINT FK_END_EMPRESA FOREIGN KEY(EMP_CODIGO) REFERENCES EMPRESA(EMP_CODIGO);
  • 17. Figura 4 – Criação do banco de dados ‘ActiveDelphi’ utilizando o pgAdminIII No formulário da figura 3, podemos utilizar a classe Empresa declarando uma variável do tipo TEmpresa no bloco Interface/var da unit. Sendo assim, todos os dados que forem digitados no formulário serão passados a este objeto instanciado, posteriormente persistido no SGBD. Fica claro que os formulários presentes neste projeto apenas são projetados para a entrada e saída de dados (visualização), pois a regra de negócios e processamento de dados fica sob a responsabilidade da classe implementada dentro do “pacote classes”. Não estamos trabalhando com o padrão de projeto MVC (Model-View-Controller), pois na aplicação exemplo não implementamos o Controller, que controla a interação entre a camada View e Model. Resumidamente trabalharemos diretamente com a View (interface gráfica) e o Model (modelo de negócio, classes). Veja abaixo como declarar uma variável Empresa do tipo TEmpresa definida na aplicação: unit untCadastroEmpresa; interface // declaração uses e classe do formulário suprimidas var Empresa: TEmpresa; No evento onShow do formulário poderíamos instanciar o objeto Empresa declarado em var, conforme abaixo: procedure TFrmCadastroEmpresa.FormShow(Sender: TObject); begin Empresa := TEmpresa.Create; // restante do código suprimido end;
  • 18. Para simplificar este artigo, não será exibido o código-fonte dos eventos do formulário apresentado na figura 3, porém nossa aplicação de controle de estoque implementada até agora pode ser baixada em http://ryanpadilha.com.br/downloads/active_delphi/controle_estoque_parte1.rar. Todos os eventos de botões, validação de dados, instanciação/recuperação de objetos do tipo Empresa, chamada de métodos de objetos, estão presentes no arquivo disponibilizado para download. Esta aplicação utiliza componentes TEdit que não possuem vínculo direto com um DataSet em particular, ou seja, com acesso direto ao banco de dados tal como os componentes do estilo TDBEdit. Então você está livre para alterá-lo conforme a sua necessidade e vontade. 3. Conclusão O paradigma orientado a objetos, exposto aqui na prática, através da construção da primeira parte de uma aplicação de controle de estoque básica, permite claramente uma maior organização de código, ou seja, as alterações futuras serão realizadas de forma fácil, pois temos uma clara visão sobre as responsabilidades de cada classe e suas interações. A manutenção (alteração) de projetos de software é um processo custoso, doloroso e na maioria das vezes produz um produto de baixa qualidade, pois as modificações podem não ser testadas adequadamente, resultando em re-trabalho pela equipe de desenvolvimento. A parte prática complementa o que vimos na teoria através do primeiro artigo, que expos uma série de vantagens em relação a obtenção de qualidade em projetos de software. Esta segunda parte propôs a modelagem do domínio de uma aplicação através da notação UML, que oferece uma documentação padronizada e simplificada do projeto de software. Adotando o diagrama de classes, implementamos classes no Delphi, relembrando os conceitos abordados no primeiro artigo, porém com um foco maior na implementação das classes e sua interação com outras classes. No terceiro e último artigo, será exposto como trabalhar com objetos de tipos definidos (classes) em um formulário, exibindo a forma como o objeto opera com os campos do formulário e como o mesmo pode ser chamado por outro formulário. Caso tenha alguma dúvida entre em contato comigo. Será um prazer ajudar. Até a terceira e última parte da série sobre a orientação a objetos. Forte Abraço!