orientação a objetos no delphi - controle de estoque (ii)

18
Orientação a Objetos no Delphi: Controle de Estoque Parte II Ryan Bruno C Padilha [email protected] 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 dorsalda 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.

Upload: ryan-padilha

Post on 27-May-2015

3.799 views

Category:

Software


6 download

TRANSCRIPT

Page 1: Orientação a Objetos no Delphi - Controle de Estoque (II)

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

Ryan Bruno C Padilha

[email protected]

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.

Page 2: Orientação a Objetos no Delphi - Controle de Estoque (II)

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

Page 3: Orientação a Objetos no Delphi - Controle de Estoque (II)

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.

Page 4: Orientação a Objetos no Delphi - Controle de Estoque (II)

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:\projetos\oo\controle_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

Page 5: Orientação a Objetos no Delphi - Controle de Estoque (II)

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;

Page 6: Orientação a Objetos no Delphi - Controle de Estoque (II)

_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;

Page 7: Orientação a Objetos no Delphi - Controle de Estoque (II)

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');

Page 8: Orientação a Objetos no Delphi - Controle de Estoque (II)

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) '+

Page 9: Orientação a Objetos no Delphi - Controle de Estoque (II)

' 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);

Page 10: Orientação a Objetos no Delphi - Controle de Estoque (II)

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;

Page 11: Orientação a Objetos no Delphi - Controle de Estoque (II)

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

Page 12: Orientação a Objetos no Delphi - Controle de Estoque (II)

é 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;

Page 13: Orientação a Objetos no Delphi - Controle de Estoque (II)

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.

Page 14: Orientação a Objetos no Delphi - Controle de Estoque (II)

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.

Page 15: Orientação a Objetos no Delphi - Controle de Estoque (II)

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),

Page 16: Orientação a Objetos no Delphi - Controle de Estoque (II)

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);

Page 17: Orientação a Objetos no Delphi - Controle de Estoque (II)

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;

Page 18: Orientação a Objetos no Delphi - Controle de Estoque (II)

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!