SlideShare ist ein Scribd-Unternehmen logo
1 von 20
Downloaden Sie, um offline zu lesen
Orientação a Objetos no Delphi: Controle de Estoque – Parte Final
Ryan Bruno C Padilha
ryan.padilha@gmail.com
http://ryanpadilha.com.br
Objetivo deste artigo
Este artigo é a parte final de uma série de três artigos onde abordamos o paradigma orientado
a objetos. No segundo artigo iniciamos a construção de uma aplicação de controle de estoque
básico, provando na prática que a OO não possui estruturas complexas de dados; ao contrário,
contempla um modelo simplificado de um conjunto de classes que se relacionam entre si, seja
através de heranças ou associações de agregação/composição. Nesta terceira parte será
revisto o modelo de domínio do controle de estoque, reforçando a utilização da notação UML,
que oferece uma documentação padronizada e simplificada do projeto de software. A
implementação em Object Pascal do restante das classes de domínio é realizado com base na
documentação referida acima, porém o objetivo agora é definir o comportamento dos objetos
de negócio instanciados na memória principal sobre a camada de visualização de dados
(view/formulário), exibindo a forma como operam com os campos do formulário e como
podem ser invocados por outro formulário.
1. Revisão do Modelo Conceitual
O modelo de domínio abordado é o controle de estoque, do qual tem por finalidade em
síntese otimizar o investimento em estoques, minimizando a necessidade de capital investido.
Nos artigos anteriores discutimos e implementamos parte do diagrama de classes exibido na
figura 1, ou seja, na segunda parte desta série implementamos no ambiente Delphi as classes:
Endereco, Pessoa, PessoaJ e Empresa; e construímos o formulário principal da aplicação, bem
como o formulário de cadastro do grupo de empresas (view). Com o referido cadastro em
funcionamento podemos cadastrar as empresas que terão controle sobre seus estoques de
produtos, realizando a entrada e saída dos mesmos seja através do formulário de manutenção
de estoque ou mesmo pela entrada de notas fiscais e/ou pela operação de venda ao
consumidor final (estes dois últimos itens citados não fazem parte do escopo do artigo, foram
apenas citados por realizarem operações sobre a quantidade de produtos em estoque). O
propósito agora é implementar as classes: Marca, Unidade, Produto e Estoque; as demais
classes Categoria, Pedido e Entrada não serão implementadas neste momento para não
fugirmos demasiadamente do objetivo do artigo e para simplificar a implementação.
Conforme citado no segundo artigo, uma boa ferramenta para realizar a modelagem de
classes, é o software Jude Community (encontrado em http://jude.change-vision.com/jude-
web/product/community.html), porém infelizmente o projeto desta ferramenta de
modelagem foi descontinuado pela empresa ChangeVision que a mantinha. Os leitores que
tiveram o interesse em baixar a ferramenta e ver como a mesma funciona ficaram frustrados.
Mas nem tudo está perdido, como é de costume a comunidade de desenvolvedores
reivindicou pela ferramenta de modelagem UML e a empresa mantenedora do projeto
retomou este projeto renomeando-o como Astah*Community, que pode ser encontrado em
http://astah.change-vision.com/en/product/astah-community.html.
A ferramenta Astah*Community é gratuita, suporta notação UML 2.0, suprindo a necessidade
de grande parte dos elementos necessários no dia-a-dia. O diagrama de classes da figura 1, foi
modelado utilizando o Astah* versão 6.4, caso queira baixar o arquivo do diagrama de classes
do modelo conceitual de controle de estoque, o mesmo pode ser encontrado em
http://ryanpadilha.com.br/downloads/active_delphi/UML_controle_estoque.jude. Seria
interessante baixar o diagrama citado, aprender a utilizar a ferramenta, assim como identificar
os elementos básicos de um diagrama de classe, pois para os leitores que acompanham os
artigos do colunista que os escreve, futuramente abordaremos outros conceitos referentes a
arquitetura e engenharia de software utilizando como base o modelo acima.
É válido observar no diagrama que o elemento Estoque tem sua definição completa, com seus
atributos e métodos. Implementar em Object Pascal esta classe e sua respectiva interação com
um formulário visual é mais trabalhoso, pois se trata de uma operação de movimentação,
frente a implementação de classes de negócios que efetuam apenas operações simples de
CRUD (acrônimo de Create, Retrieve, Update, Delete) como foi abordado na definição dos
elementos Empresa e Endereco.
1.1 O Contexto da classe Estoque
A classe Estoque está associada a classe Empresa, pois uma empresa pode possuir vários
produtos em estoque do qual queira controlar e manter um histórico de entrada e saída do
mesmo. Uma aplicação de controle de estoque pode controlar o estoque de várias empresas,
por isso implementamos um cadastro de grupo de empresas, para que possamos cadastrar as
empresas que controlarão seus estoques. A cardinalidade entre Empresa e Estoque é de 1..*
(um para vários), ou seja, cada empresa controla apenas um único estoque (individualmente),
que é constituído por vários produtos, porém o estoque controlado por cada empresa pode ter
um saldo diferente de um mesmo produto, sendo que há uma separação lógica do mesmo
dentro do banco de dados.
Em relação a classe Produto, esta se relaciona com a classe Estoque através da associação com
cardinalidade 1..* (um para vários), onde para um determinado produto há a ocorrência de
vários registros em um estoque, e o mesmo possui apenas uma referência ao produto.
Resumidamente encontramos um produto com identificação única (através do ID) dentro de
um estoque definindo o tipo de movimentação (E/S) e a quantidade informada pelo usuário da
aplicação. Esta definição ficará mais clara até o final do artigo. O elemento Produto está
associado também a um elemento Marca, cardinalidade de *..1, um produto tem uma única
marca e uma marca pode pertencer a vários produtos; e pode conter várias medidas de
Unidade, cardinalidade de *..*, um produto pode conter várias unidades de medida e as
unidades de medidas pertencem a vários produtos.
Vejamos em mais detalhes o que a classe Estoque possui em sua definição, detalhando as
assinaturas dos métodos implementados: 1) public Validar(): boolean – efetua a validação do
estado do objeto instanciado em memória, tornando-o consistente; 2) public Movimentacao():
boolean – a movimentação de entrada e saída de produtos de uma determinada empresa no
estoque é realizado através da implementação deste método, que é também o principal
método da classe; public ConsultarSaldo(): Double – consulta e retorna o saldo atual de um
produto pertencente ao estoque de determinada empresa (saldo entrada – saldo saída); public
getObject(Id: String): boolean – retorna a movimentação do estoque de um produto através de
seu ID (código); public getObjects(): boolean – toda a movimentação efetuada no estoque de
uma empresa é retornado; public getObjects(Id: String): boolean – através deste método é
exibido na Grid do formulário visual (FrmControleEstoque) o histórico de movimentação de um
produto especificado pelo argumento ID (código).
Figura 1 – Diagrama de Classe Simplificado. Domínio: Controle de Estoque.
2. Objetos de negócio e formulários: Divisão de responsabilidades em duas camadas
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.
Adotando o exemplo criado anteriormente na segunda parte da série, continuaremos a
implementar o aplicação de controle de estoque. Para quem irá começar a acompanhar o
desenvolvimento da aplicação deste ponto, o código-fonte de exemplo pode ser encontrado
em http://activedelphi.com.br/downloads/orientacao_objetos.rar. A IDE Delphi 7 Update2
está sendo utilizado no desenvolvimento, pois o objetivo desta série sobre Orientação a
Objetos e seus conceitos adjacentes está voltado a implementação do modelo conceitual e
não focado na utilização de componentes específicos de software. Para realizar a persistência
de dados estamos utilizando o SGBD objeto-relacional PostgreSQL 8.3, que pode ser
encontrado em http://www.postgresql.org.
Com o Delphi aberto, procure pelo projeto “ControleEstoque”, que foi salvo anteriormente no
diretório “d:projetosoocontrole_estoque” (ou no diretório de sua preferência), abra-o e o
mesmo será exibido dentro da IDE. O menu principal da aplicação fora definido anteriormente,
restando apenas criar os formulários dos itens de menu. Iremos implementar apenas o
formulário de Cadastro de Produto e o de Movimentação de Estoque, ficando a criação do
restante dos cadastros sugeridos a critério do leitor, pois ao termino deste artigo todos os
princípios básicos de construção de formulários e sua interação com objetos de negócios
(classes) definidos no escopo da aplicação serão abordados.
2.1 Classes de negócio
Seguindo a mesma linha de desenvolvimento, comecemos com a implementação das classes
de negócio, mais especificamente com a classe concreta Unidade; a responsabilidade dessa
classe é conter dados relacionados com as unidades de medidas utilizadas pelos produtos.
Adicione uma nova unit ao projeto através do Menu File – New – Unit, salve-a no diretório
“classes” como clUnidade.pas. No bloco interface/implementation da unit declare/implemente
a classe conforme abaixo:
unit clUnidade;
interface
type
TUnidade = class(TObject)
private
// métodos privados
// métodos acessores suprimidos. getters / setters.
function Insert(): Boolean;
function Update(): Boolean;
protected
// declaração de atributos
_codigo: String;
_descricao: String;
_sigla: String;
public
// declaração das propriedades da classe, encapsulamento de atributos
property Codigo: String read getCodigo write setCodigo;
property Descricao: String read getDescricao write setDescricao;
property Sigla: String read getSigla write setSigla;
// declaração de métodos públicos
function Validar(): Boolean;
function Merge(): Boolean;
function Delete(): Boolean;
function getObject(Id: String): Boolean;
function getObjects(): Boolean;
function getField(campo: String; coluna: String): String;
end;
const
TABLENAME = 'UNIDADE';
implementation
uses clUtil, dmConexao, SysUtils, Dialogs;
{ TUnidade }
// implementação suprimida, para não estender muito o artigo
end.
Depois da definição e implementação da classe acima, precisamos agora implementar a classe
Marca que é responsável por conter dados relacionados as marcas dos produtos
comercializados por uma empresa do ramo atacadista/varejista. Adicione uma nova unit ao
projeto através do Menu File – New – Unit, salve-a no diretório “classes” como clMarca.pas.
No bloco interface da unit declare a classe conforme abaixo:
unit clMarca;
interface
type
TMarca = class(TObject)
private
// métodos privados
// métodos acessores suprimidos. getters / setters.
function Insert(): Boolean;
function Update(): Boolean;
protected
// declaração de atributos
_codigo: String;
_descricao: String;
public
// declaração das propriedades da classe, encapsulamento de atributos
property Codigo: String read getCodigo write setCodigo;
property Descricao: String read getDescricao write setDescricao;
// declaração de métodos públicos
function Validar(): Boolean;
function Merge(): Boolean;
function Delete(): Boolean;
function getObject(Id: String): Boolean;
function getObjects(): Boolean;
function getField(campo: String; coluna: String): String;
end;
const
TABLENAME = 'MARCA';
implementation
uses clUtil, dmConexao, SysUtils, Dialogs;
{ TMarca }
// implementação suprimida, para não estender muito o artigo
end.
Implementamos as classes Unidade e Marca a princípio pois as mesmas estão associadas com
a classe Produto. Na notação UML identificada na figura 1, esta associação possui a definição
de navegabilidade, ou seja, a classe Produto contém referência a objetos do tipo Unidade e
Marca. Logo abaixo na implementação da classe Produto será possível visualizar atributos
declarados com os tipos definidos por nós, e no método construtor da classe a
responsabilidade em instanciar os objetos referenciados. É denotado aqui a interação entre os
objetos de negócio, compondo um rico ambiente onde as diversas unidades de software
(objetos), que inter-relacionadas formam o escopo de uma aplicação, definindo a divisão de
responsabilidades em classes de negócios, resultando em uma coesão satisfatória e uma
granularidade razoável.
Adicione uma nova unit ao projeto através do Menu File – New – Unit, salve-a no diretório
“classes” como clProduto.pas. Nesta unit declaramos a classe conforme abaixo:
unit clProduto;
interface
// utilização das units declaradas anteriormente, classes de negócios
uses clUnidade, clMarca;
type
TProduto = class(TObject)
private
// métodos privados
// métodos acessores suprimidos. getters / setters.
function Insert(): Boolean;
function Update(): Boolean;
protected
// declaração de atributos
_codigo: String;
_codigoPrincipal: String;
_descricao: String;
_descReduzido: String;
_status: Boolean;
_unidade: TUnidade; //
_marca: TMarca; //
// categoria...
public
// método construtor definido por nós
constructor Create;
// declaração das propriedades da classe, encapsulamento de atributos
property Codigo: String read getCodigo write setCodigo;
property CodigoPrincipal: String read getCodigoPrinc write setCodigoPrinc;
property Descricao: String read getDescricao write setDescricao;
property DescReduzido: String read getDescReduzido write setDescReduzido;
property Status: Boolean read getStatus write setStatus;
property Unidade: TUnidade read getUnidade write setUnidade;
property Marca: TMarca read getMarca write setMarca;
// na linha acima antes do ponto e virgula (setStatus) pressione Ctrl + Shift + C
// para gerar os métodos acessores getter e setter automaticamente
// declaração de métodos públicos
function Validar(): Boolean;
function Merge(): Boolean;
function Delete(): Boolean;
function getObject(Id: String): Boolean;
function getObjects(): Boolean;
function getField(campo: String; coluna: String): String;
end;
const
TABLENAME = 'PRODUTO';
implementation
uses clUtil, dmConexao, SysUtils, Dialogs;
{ TProduto }
// método construtor
constructor TProduto.Create;
begin
_unidade := TUnidade.Create; // instanciação do objeto Unidade
_marca := TMarca.Create; // instanciação do objeto Marca
end;
// implementação suprimida, para não estender muito o artigo
end.
Através desta série de artigos sobre orientação a objetos no Delphi, adotamos como exemplo
prático o desenvolvimento de uma aplicação de controle de estoque com o intuito de
contemplar a maioria dos conceitos apresentados teoricamente na primeira parte da série. E
neste momento será definido a classe principal de nosso projeto, ou seja, a classe Estoque que
é responsável por controlar o estoque dos produtos de uma determinada empresa através das
operações de entrada e saída. Visualizando a modelagem da figura 1, fica claro que o elemento
Estoque está no cerne do diagrama de classes, pois está relacionado com a classe Produto e
Empresa, que conseqüentemente tem uma rica interação com outros elementos do escopo. É
interessante comentar sobre a associação e navegabilidade entre a classe Estoque-Produto e
Estoque-Empresa, onde em um estoque efetuamos operações de entrada/saída de produtos
definindo a quantidade e valor de custo do mesmo, sobre o estoque de uma determinada
empresa em particular. A descrição sobre a navegabilidade pode ser sintetizada através da
notação de cardinalidade citado logo no início deste artigo.
Adicione uma nova unit ao projeto através do Menu File – New – Unit, salve-a no diretório
“classes” como clEstoque.pas. Como esta classe de negócio é o foco principal da aplicação,
será apresentado o código-fonte completo da mesma (exceto os métodos acessores – get/set).
Nesta unit declaramos a classe conforme abaixo:
unit clEstoque;
interface
// utilização das units declaradas anteriormente, classes de negócios
uses clProduto, clEmpresa;
type
TEstoque = class(TObject)
private
// métodos privados
// métodos acessores suprimidos. getters / setters.
protected
// declaração de atributos
_codigo: String;
_data: TDateTime;
_hora: TDateTime;
_documento: String;
_saldo: Double;
_vlrCusto: Currency;
_tipoMov: String;
_quantidade: Double;
_flag: Boolean;
_produto: TProduto;
_empresa: TEmpresa;
public
// método construtor definido por nós
constructor create;
// declaração das propriedades da classe, encapsulamento de atributos
property Codigo: String read getCodigo write setCodigo;
property Data: TDateTime read getData write setData;
property Hora: TDateTime read getHora write setHora;
property Documento: String read getDocumento write setDocumento;
property Saldo: Double read getSaldo write setSaldo;
property VlrCusto: Currency read getVlrCusto write setVlrCusto;
property TipoMov: String read getTipoMov write setTipoMov;
property Quantidade: Double read getQuantidade write setQuantidade;
property Flag: Boolean read getFlag write setFlag;
property Produto: TProduto read getProduto write setProduto;
property Empresa: TEmpresa read getEmpresa write setEmpresa;
// declaração de métodos públicos
function Validar(): Boolean;
function Movimentacao(): Boolean;
function ConsultarSaldo(): Double;
function getObject(Id: String): Boolean;
function getObjects: Boolean; overload;
function getObjects(Id: String): Boolean; overload;
end;
const
TABLENAME = 'ESTOQUE';
implementation
uses SysUtils, dmConexao, Dialogs, clUtil, DB, ZAbstractRODataset;
{ TEstoque }
// método construtor
constructor TEstoque.create;
begin
_produto := TProduto.Create; // instanciação do objeto Produto
_empresa := TEmpresa.Create; // instanciação do objeto Empresa
end;
// implementação suprimida dos métodos acessores (get/set), para não estender muito o artigo
// todos os métodos contendo regras de negócios estão relacionados abaixo
function TEstoque.ConsultarSaldo(): Double;
begin
Try
Result := 0;
with Conexao.QryGetObject do begin
Close;
SQL.Clear;
SQL.Text := 'SELECT SUM(EST_QUANTIDADE) - COALESCE((SELECT SUM(EST_QUANTIDADE) AS EST_SALDO FROM
'+ TABLENAME +
' WHERE PRO_CODIGO =:PRODUTO AND EMP_CODIGO =:EMPRESA AND EST_TIPO_MOV = '''+'S'+'''), 0) AS
EST_SALDO '+
' FROM '+ TABLENAME +
' WHERE PRO_CODIGO =:PRODUTO AND EMP_CODIGO =:EMPRESA AND EST_TIPO_MOV = '''+'E'+''' ';
ParamByName('PRODUTO').AsString := Self.Produto.Codigo;
ParamByName('EMPRESA').AsString := Self.Empresa.Codigo;
Open;
First;
end;
if Conexao.QryGetObject.RecordCount > 0 then
Result := Conexao.QryGetObject.FieldByName('EST_SALDO').AsFloat;
Except
on E : Exception do
ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message);
end;
end;
function TEstoque.Movimentacao: Boolean;
begin
// Movimentação de Estoque
Try
Result := False;
with Conexao.QryCRUD do begin
Close;
SQL.Clear;
SQL.Text := 'INSERT INTO '+ TABLENAME +' (PRO_CODIGO, EMP_CODIGO, EST_DATA, EST_HORA,
EST_DOCUMENTO, EST_SALDO, '+
' EST_VLR_CUSTO, EST_TIPO_MOV, EST_QUANTIDADE) '+
' VALUES (:PRODUTO, :EMPRESA, :DATA, :HORA, :DOCUMENTO, :SALDO, :VLR_CUSTO, :TIPO_MOV,
:QUANTIDADE)';
ParamByName('PRODUTO').AsString := Self.Produto.Codigo;
ParamByName('EMPRESA').AsString := Self.Empresa.Codigo;
ParamByName('DATA').AsDateTime := Self.Data;
ParamByName('HORA').AsDateTime := Now; // hora atual
ParamByName('DOCUMENTO').AsString := Self.Documento;
// verificando o tipo de movimento
if Self.TipoMov = 'E' then
ParamByName('SALDO').AsFloat := (Self.ConsultarSaldo + Self.Quantidade)
else
ParamByName('SALDO').AsFloat := (Self.ConsultarSaldo - Self.Quantidade);
ParamByName('VLR_CUSTO').AsCurrency := Self.VlrCusto;
ParamByName('TIPO_MOV').AsString := Self.TipoMov;
ParamByName('QUANTIDADE').AsFloat := Self.Quantidade;
ExecSQL;
end;
Result := True;
Except
on E : Exception do
ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message);
end;
end;
function TEstoque.getObjects: Boolean;
begin
Try
Result := False;
with Conexao.QryGetObject do begin
Close;
SQL.Clear;
SQL.Text := 'SELECT * FROM '+ TABLENAME +' ORDER BY EST_CODIGO';
Open;
First;
end;
if Conexao.QryGetObject.RecordCount > 0 then
Result := True;
Except
on E : Exception do
ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message);
end;
end;
// pegar movimentação de estoque pelo ID (PRODUTO)
function TEstoque.getObject(Id: String): Boolean;
begin
try
Result := False;
if TUtil.Empty(Id) then
Exit;
with Conexao.QryGetObject do begin
Close;
SQL.Clear;
SQL.Text := 'SELECT * FROM '+ TABLENAME +' WHERE PRO_CODIGO =:CODIGO AND EMP_CODIGO =:EMPRESA';
ParamByName('CODIGO').AsString := Id;
ParamByName('EMPRESA').AsString := Self.Empresa.Codigo;
Open;
First;
end;
if Conexao.QryGetObject.RecordCount > 0 then begin
Self.Codigo := Conexao.QryGetObject.FieldByName('EST_CODIGO').AsString;
Self.Produto.Codigo := Conexao.QryGetObject.FieldByName('PRO_CODIGO').AsString;
Self.Data := Conexao.QryGetObject.FieldByName('EST_DATA').AsDateTime;
Self.Hora := Conexao.QryGetObject.FieldByName('EST_HORA').AsDateTime;
Self.Documento := Conexao.QryGetObject.FieldByName('EST_DOCUMENTO').AsString;
Self.Saldo := Conexao.QryGetObject.FieldByName('EST_SALDO').AsFloat;
Self.VlrCusto := Conexao.QryGetObject.FieldByName('EST_VLR_CUSTO').AsCurrency;
Self.TipoMov := Conexao.QryGetObject.FieldByName('EST_TIPO_MOV').AsString;
Self.Quantidade := Conexao.QryGetObject.FieldByName('EST_QUANTIDADE').AsFloat;
Self.Flag := Conexao.QryGetObject.FieldByName('EST_FLAG').AsBoolean;
Result := True;
end;
Except
on E : Exception do
ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message);
end;
end;
function TEstoque.Validar: Boolean;
begin
// validação de atributos
if Length(DateToStr(_data)) <> 10 then begin
ShowMessage('Data Inválida!');
Result := false;
Exit;
end
else if _quantidade = 0 then begin
ShowMessage('Quantidade Inválida!');
Result := False;
Exit;
end;
Result := True;
end;
function TEstoque.getObjects(Id: String): Boolean;
begin
Try
Result := False;
with Conexao.QryEstoque do begin
Close;
SQL.Clear;
SQL.Text := 'SELECT * FROM '+ TABLENAME +' WHERE PRO_CODIGO =:CODIGO AND EMP_CODIGO =:EMPRESA
ORDER BY EST_CODIGO';
ParamByName('CODIGO').AsString := Id;
ParamByName('EMPRESA').AsString := Self.Empresa.Codigo;
Open;
First;
end;
if Conexao.QryGetObject.RecordCount > 0 then begin
Self.getObject(Id);
Result := True;
end;
Except
on E : Exception do
ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message);
end;
end;
end.
Agora que temos o diagrama de classes representado pela figura 1 implementado totalmente
em Object Pascal (exceto a classe Categoria), vamos construir o formulário que irá persistir os
objetos do tipo Produto e outro que efetue o controle de estoque, através da movimentação
de produtos operando a entrada e saída de produtos, atualizando seu saldo corrente.
2.2 A camada de visualização de dados: O formulário
Utilizando o conceito RAD (Rapid Application Development - Desenvolvimento Rápido de
Aplicativos) da IDE Delphi construímos formulários visuais com rapidez e facilidade, obtemos
uma velocidade ainda maior no desenvolvimento pois a implementação de toda a lógica da
aplicação já está definida. Com isso os formulários passam a atuar definitivamente apenas
como instrumentos de entrada e visualização de dados, tendo sua responsabilidade resumida
a isto.
Não é necessário especificar todos os componentes visuais e suas respectivas propriedades,
estou assumindo que a maioria dos leitores possui plenos conhecimentos em construção de
formulários visuais utilizando o Delphi. Para a construção do formulário de Cadastro de
Produtos tomemos como base o layout sugerido pela figura 2. E para o formulário principal da
aplicação, o de Controle de Estoque adotemos o layout proposto pela figura 3.
Figura 2 – Formulário de Cadastro de Produto.
No formulário da figura 2, podemos utilizar a classe Produto declarando uma variável do tipo
TProduto no bloco interface/var da unit. Todos os dados digitados no formulário são atribuídos
as propriedades da classe Produto, alterando o estado do objeto instanciado, que é então
persistido no SGBD. Toda a interação efetuada com o formulário ocorre através de eventos,
que quando disparados executam algum procedimento dentro da aplicação. Para exemplificar
o que acabados de descrever, ao clicarmos sobre o botão Salvar (ícone disquete), é invocado o
evento onClick sppSalvarClick(Sender: TObject) que contempla a seguinte declaração:
procedure TFrmCadastroProduto.sppSalvarClick(Sender: TObject);
var
Operacao: String;
begin
Operacao := 'U';
// atribuindo os valores digitados no formulário as propriedades do objeto Produto
Produto.Codigo := edtCodigo.Text;
Produto.CodigoPrincipal := edtCodigoPrinc.Text;
Produto.Descricao := edtDescricao.Text;
Produto.DescReduzido := edtDescRed.Text;
if cmbStatus.ItemIndex = 0 then
Produto.Status := false
else
Produto.Status := true;
if TUtil.Empty(Produto.Codigo) then
Operacao := 'I';
if Produto.Validar() then
if Produto.Merge() then begin
if Operacao = 'I' then
ShowMessage('Registro Gravado com Sucesso!')
else
ShowMessage('Registro Atualizado com Sucesso!');
Conexao.QryProduto.Close;
Conexao.QryProduto.Open;
sppCancelarClick(Self);
end;
end;
Antes mesmo da chamada do método Merge() que é responsável por persistir o objeto no
banco de dados, as propriedades do objeto são alteradas através da atribuição dos valores
digitados no formulário. Notamos que o formulário apenas “repassa” os valores ao objeto e o
mesmo se encarrega de validar e persistir os dados efetivamente. O que acabamos de
descrever aqui é um modelo de divisão de responsabilidade onde cada unidade de software é
responsável por determinada atividade.
Temos mais dois eventos declarados no formulário da figura 2 que serão abordados – o
procedimento privado onClick sppCancelarClick(Sender: TObject) que limpa os campos do
formulário, destrói e instancia novamente o objeto do tipo Produto, renovando seu estado.
Quando clicamos no botão cancelar (ícone X), o seguinte procedimento é executado:
procedure TFrmCadastroProduto.sppCancelarClick(Sender: TObject);
begin
TUtil.LimparFields(FrmCadastroProduto);
Produto := nil;
Produto := TProduto.Create;
edtDescricao.SetFocus;
end;
O segundo evento citado no parágrafo acima é o procedimento onClick sppExcluirClick(Sender:
TObject) que deleta um objeto Produto da tabela relacional se a propriedade código do objeto
instanciado em memória estiver com valor definido e for consistente. Quando clicamos no
botão excluir (ícone lixeira), o seguinte evento é disparado:
procedure TFrmCadastroProduto.sppExcluirClick(Sender: TObject);
begin
if TUtil.Empty(Produto.Codigo) then
Exit;
if MessageBox(Application.Handle, 'Deseja Realmente Excluir o Registro?', 'Controle Estoque', MB_ICONQUESTION
+ MB_YESNO + MB_DEFBUTTON2) = ID_NO then
Exit;
if TUtil.NotEmpty(Produto.Codigo) then begin
if NOT Produto.Delete then
ShowMessage('Erro ao Excluir o Registro.')
else begin
TUtil.LimparFields(FrmCadastroProduto);
Conexao.QryProduto.Close;
Conexao.QryProduto.Open;
end;
end;
end;
Com o cadastro de produto em pleno funcionamento podemos realizar operações CRUD com o
mesmo, necessitando a princípio inserir produtos que serão controlados pelo formulário da
figura 3, o controle de estoque. Neste formulário selecionamos a empresa da qual estamos
controlando o estoque de produtos, cada empresa possui um estoque independente conforme
citado anteriormente. No campo “Código do Produto” digitamos o código do produto do qual
queiramos pesquisar e visualizar o histórico de movimentação de entrada e saída, assim como
seu saldo atual em estoque. Após um produto ser encontrado, seu estado é recuperado do
banco de dados e definido na instancia do objeto em memória (objeto Estoque.Produto), o
componente visual groupBox de movimentação é exibido, permitindo a movimentação de
Entrada(1) ou Saída(2) do produto – informando uma quantidade (número de ponto flutuante
positivo), valor monetário de custo (compra), número do documento do qual origina-se o
movimento. Ao clicar no tipo de movimento (componente radioGroup) o botão movimentar é
ativado e sua propriedade caption é modificada de acordo com o tipo selecionado. Ao clicar no
referido botão o seguinte evento é disparado:
procedure TFrmControleEstoque.btnMovimentarClick(Sender: TObject);
begin
if MessageBox(Application.Handle, 'Deseja Realmente Movimentar o Estoque?', 'Controle Estoque',
MB_ICONQUESTION + MB_YESNO + MB_DEFBUTTON2) = ID_NO then
Exit;
case rdgTipo.ItemIndex of
0 : Estoque.TipoMov := 'E'; // entrada
1 : Estoque.TipoMov := 'S'; // saída
end;
// alterando o estado do objeto Estoque
Estoque.Data := StrToDate(mskData.Text);
Estoque.Quantidade := StrToFloat(edtQuantidade.Text);
Estoque.VlrCusto := StrToFloat(edtValorCusto.Text);
Estoque.Documento := edtDocumento.Text;
if Estoque.Validar() then
if Estoque.Movimentacao() then
LimparMovimento
else
ShowMessage('Problemas ao Efeturar Movimentação no Estoque!');
end;
Figura 3 – Formulário de Controle de Estoque (movimentação).
O método Movimentacao(): boolean é o principal método definido no escopo da aplicação,
executando a movimentação de estoque, atualizando o saldo em estoque do produto
selecionado. Caso tenha alguma dúvida em como a regra está implementada na classe
clEstoque.pas verifique novamente a declaração do código da classe definida anteriormente. O
formulário da figura 3 pode ser invocado também através do cadastro de produtos, clicando
no botão “Verificar Estoque”; se algum produto estivar selecionado, ou seja, sendo visualizado
no cadastro de produto, o mesmo será passado por referência ao objeto declarado como
public ProdutoRef na unit do formulário de controle de estoque. O evento onClick do botão
citado é definido na unit untCadastroProduto.pas como:
procedure TFrmCadastroProduto.btnEstoqueClick(Sender: TObject);
begin
if NOT Assigned(FrmControleEstoque) then
FrmControleEstoque := TFrmControleEstoque.Create(Application);
// passando o Objeto Produto para o outro formulário (estoque)
// em cada formulário encontramos um objeto do tipo produto
// sendo possível passar o estado de um objeto de um formulário
// ao objeto de outro formulário
if TUtil.NotEmpty(Produto.Codigo) then
FrmControleEstoque.ProdutoRef := Produto;
FrmControleEstoque.ShowModal;
end;
O processo de transferir o estado de um objeto instanciado em um formulário a outro é
comumente utilizado e de simples utilização. Este procedimento é utilizado também em
formulários de pesquisa, que geralmente são invocados por formulários de cadastro.
Na segunda parte da série criamos o banco de dados “ActiveDelphi” através da ferramenta
gráfica pgAdminIII (acompanha a instalação do SGBD PostgreSQL), execute-a, com ela aberta
dê dois cliques no hostname onde o banco de dados fora criado, realize o login, forneça
apenas a senha que foi definida ao usuário do banco. No item Banco de Dados, expanda a lista
de bancos de dados existentes e procure pelo nome “ActiveDelphi”, selecione-o; através do
editor SQL (clicando no ícone SQL) execute o seguinte script SQL DDL (Data Definition
Language):
-- MARCA
CREATE TABLE MARCA(
MAR_CODIGO SERIAL NOT NULL,
MAR_DESCRICAO VARCHAR(100) NOT NULL
);
ALTER TABLE MARCA ADD CONSTRAINT PK_MARCA PRIMARY KEY(MAR_CODIGO);
-- POPULANDO A TABELA MARCA
INSERT INTO MARCA (MAR_DESCRICAO) VALUES ('DUREX');
INSERT INTO MARCA (MAR_DESCRICAO) VALUES ('EATON');
INSERT INTO MARCA (MAR_DESCRICAO) VALUES ('INDISA');
INSERT INTO MARCA (MAR_DESCRICAO) VALUES ('LUCIFLEX');
INSERT INTO MARCA (MAR_DESCRICAO) VALUES ('PERKINS');
INSERT INTO MARCA (MAR_DESCRICAO) VALUES ('STAHL');
-- UNIDADE
CREATE TABLE UNIDADE(
UND_CODIGO SERIAL NOT NULL,
UND_DESCRICAO VARCHAR(100) NOT NULL,
UND_SIGLA VARCHAR(5) UNIQUE NOT NULL
);
ALTER TABLE UNIDADE ADD CONSTRAINT PK_UNIDADE PRIMARY KEY(UND_CODIGO);
-- POPULANDO A TABELA UNIDADE
INSERT INTO UNIDADE (UND_DESCRICAO, UND_SIGLA) VALUES ('CAIXA', 'CXA');
INSERT INTO UNIDADE (UND_DESCRICAO, UND_SIGLA) VALUES ('UNIDADE', 'UND');
INSERT INTO UNIDADE (UND_DESCRICAO, UND_SIGLA) VALUES ('KILO', 'KG');
INSERT INTO UNIDADE (UND_DESCRICAO, UND_SIGLA) VALUES ('METRO', 'MT');
-- PRODUTO
CREATE TABLE PRODUTO(
PRO_CODIGO SERIAL NOT NULL,
PRO_C_PRINCIPAL VARCHAR(20),
PRO_STATUS BOOLEAN,
PRO_DESCRICAO VARCHAR(200),
PRO_DESC_REDUZIDO VARCHAR(50),
MAR_CODIGO INTEGER,
UND_CODIGO INTEGER
);
ALTER TABLE PRODUTO ADD CONSTRAINT PK_PRODUTO PRIMARY KEY(PRO_CODIGO);
ALTER TABLE PRODUTO ADD CONSTRAINT FK_PRODUTO_MARCA FOREIGN KEY(MAR_CODIGO)
REFERENCES MARCA(MAR_CODIGO);
ALTER TABLE PRODUTO ADD CONSTRAINT FK_PRODUTO_UNIDADE FOREIGN KEY(UND_CODIGO)
REFERENCES UNIDADE(UND_CODIGO);
-- ESTOQUE
CREATE TABLE ESTOQUE(
EST_CODIGO SERIAL NOT NULL,
PRO_CODIGO INTEGER NOT NULL, -- PRODUTO
EMP_CODIGO INTEGER NOT NULL, -- EMPRESA
EST_DATA DATE NOT NULL,
EST_HORA TIME NOT NULL,
EST_DOCUMENTO VARCHAR(20),
EST_SALDO NUMERIC(15,5),
EST_VLR_CUSTO NUMERIC(15,5),
EST_TIPO_MOV CHAR,
EST_QUANTIDADE NUMERIC(15,5),
EST_FLAG BOOLEAN
);
ALTER TABLE ESTOQUE ADD CONSTRAINT PK_ESTOQUE PRIMARY KEY(EST_CODIGO);
ALTER TABLE ESTOQUE ADD CONSTRAINT FK_ESTOQUE_PRODUTO FOREIGN KEY(PRO_CODIGO)
REFERENCES PRODUTO(PRO_CODIGO);
ALTER TABLE ESTOQUE ADD CONSTRAINT FK_ESTOQUE_EMPRESA FOREIGN KEY(EMP_CODIGO)
REFERENCES EMPRESA(EMP_CODIGO);
Terminamos neste momento a aplicação de controle de estoque, que poderá ser baixada na
integra em http://ryanpadilha.com.br/downloads/active_dephi/controle_estoque_parte2.rar.
Caso algum leitor tenha alguma sugestão, crítica ou elogio referente ao que foi abordado e
implementado aqui, entre em contato com este colunista que vos escreve.
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.
2.3 Justificativa da arquitetura em duas camadas
Alguns leitores podem argumentar neste momento: Em aplicações que utilizam o paradigma
estruturado, o formulário trata os dados digitados, não repassa informação a nenhum outro
lugar, apenas persiste a informação em uma tabela relacional utilizando componentes de
acesso direto a banco de dados (os famosos componentes DB<objeto>), a unit do formulário
contem toda a lógica, resumindo é muito rápido desenvolver software assim. E com a
arquitetura proposta neste artigo temos a divisão de responsabilidades em duas camadas
(model e view), onde a implementação fica separada uma da outra e que no final da um pouco
mais de trabalho em implementar. Afinal o que ganhamos com a utilização desse modelo de
duas camadas ?
Sinceramente este questionamento ocorre com freqüência, a maioria é feita por
desenvolvedores originados do modelo estrutural de desenvolvimento. A orientação a objetos
é uma evolução conceitual dentro do ramo da engenharia de software que vem se mostrando
cada dia mais poderosa e flexível. Porém não é a palavra final tratando-se de desenvolvimento
de software, com certeza a evolução caminha e novas tecnologias e conceitos surgem,
complementando o modelo anteriormente proposto pelos pesquisadores e engenheiros de
software.
Retornando a pergunta provavelmente feita por muitos leitores, temos vários conceitos
envolvidos neste modelo proposto: 1) O princípio de responsabilidade única (SRP – Single
Responsability Principle) – onde cada classe ou até mesmo unit detêm responsabilidade
exclusiva dentro do contexto da aplicação, aumentando significativamente a coesão das
unidades de software; 2) Arquitetura de software em camadas – a manutenção do software
que corresponde em média a 80% do investimento é facilitado pois temos divisão de
implementação em camadas, reduzindo o acoplamento, ou seja, tornando as classes/units
mais dependentes umas das outras; 3) Nível satisfatório de coesão e acoplamento – através da
definição de classes coesas fica mais fácil de manter e estender suas funcionalidade assim
como mantemos um conjunto de classes de regras de negócios que são auto-independentes
da plataforma, ou seja, podemos ter as mesmas classes de negócios com apenas a camada de
visualização (view) distintas – desktop ou intraweb, pois as temos um baixo acoplamento entre
as camadas.
3. Conclusão
Esta série de três partes sobre o paradigma orientado a objetos tem seu encerramento no
fechamento deste artigo, do qual teve como objetivo revisar tudo o que fora visto até então
sobre os conceitos teóricos e práticos e reforçar o que ainda não tinha sido abordado.
Introduzimos o leitor no “mundo OO” exibindo suas vantagens e desvantagens, as dificuldades
encontradas por programadores que desejam iniciar-se neste contexto e as tecnologias
adjacentes que auxiliam o desenvolvedor a alcançar a qualidade de software. A teoria
apresentada fora implementada na prática, comprovando que é possível sim desenvolver
aplicativos robustos e flexíveis, orientados a objeto, utilizando o Object Pascal que é pouco
difundido entre os desenvolvedores da comunidade Delphi, pois há uma carência de material
de qualidade sobre o assunto.
A aplicação de controle de estoque teve sua arquitetura definida em duas camadas
(model/view), objetivando uma alta coesão e baixo acoplamento entre unidades de software,
porém em uma medida satisfatória de granularidade. Este conceito de duas camadas pode ser
substituída pelo padrão de projeto MVC (model/view/controller) melhorando o escopo de
controle de estoque adotado. Em um próximo artigo veremos conceitualmente como este
padrão de projeto opera e como pode ser implementado na prática sem maiores dificuldades.
Fico contente e gratificado em ter ajudado os leitores a esclarecer suas dúvidas sobre
orientação a objetos. A área de Engenharia de Software é ampla e contempla muitos conceitos
e práticas das quais serão abordadas em outras oportunidades. Caso algum leitor tenha
sugestões de artigos sobre a área citada entre em contato comigo. Será uma honra escrever
novos artigos sobre arquitetura e engenharia.
Caso tenha alguma dúvida entre em contato comigo. Será um prazer ajudar.
Forte Abraço a todos os leitores que acompanharam a série Delphi OO – teórico e prático!

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (20)

HOW TO CREATE A MODULE IN ODOO
HOW TO CREATE A MODULE IN ODOOHOW TO CREATE A MODULE IN ODOO
HOW TO CREATE A MODULE IN ODOO
 
Mvc delphi
Mvc delphiMvc delphi
Mvc delphi
 
Domain Driven Design Quickly
Domain Driven Design QuicklyDomain Driven Design Quickly
Domain Driven Design Quickly
 
Prototype pattern
Prototype patternPrototype pattern
Prototype pattern
 
Design Pattern For C# Part 1
Design Pattern For C# Part 1Design Pattern For C# Part 1
Design Pattern For C# Part 1
 
Domain driven design and model driven development
Domain driven design and model driven developmentDomain driven design and model driven development
Domain driven design and model driven development
 
concept of oops
concept of oopsconcept of oops
concept of oops
 
Basic oop concepts - C++
Basic oop concepts - C++Basic oop concepts - C++
Basic oop concepts - C++
 
Package Diagram
Package DiagramPackage Diagram
Package Diagram
 
Introduction to DDD
Introduction to DDDIntroduction to DDD
Introduction to DDD
 
File Organization
File OrganizationFile Organization
File Organization
 
Four Pillers Of OOPS
Four Pillers Of OOPSFour Pillers Of OOPS
Four Pillers Of OOPS
 
Introduction to OOP concepts
Introduction to OOP conceptsIntroduction to OOP concepts
Introduction to OOP concepts
 
Cardinality and participation constraints
Cardinality and participation constraintsCardinality and participation constraints
Cardinality and participation constraints
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
Programação orientada a objetos
Programação orientada a objetosProgramação orientada a objetos
Programação orientada a objetos
 
Slides 6 design of sw arch using add
Slides 6 design of sw arch using addSlides 6 design of sw arch using add
Slides 6 design of sw arch using add
 
Multiple choice questions for Java io,files and inheritance
Multiple choice questions for Java io,files and inheritanceMultiple choice questions for Java io,files and inheritance
Multiple choice questions for Java io,files and inheritance
 
Oops concepts
Oops conceptsOops concepts
Oops concepts
 
Oomd unit1
Oomd unit1Oomd unit1
Oomd unit1
 

Andere mochten auch

Programação orientada a objetos em delphi
Programação orientada a objetos em delphiProgramação orientada a objetos em delphi
Programação orientada a objetos em delphiHelder Lopes
 
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
 
FireDAC - Embarcadero Conference 2015
FireDAC - Embarcadero Conference 2015FireDAC - Embarcadero Conference 2015
FireDAC - Embarcadero Conference 2015Guinther Pauli
 
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
 
Projeto de Sistemas - Aula005
Projeto de Sistemas - Aula005Projeto de Sistemas - Aula005
Projeto de Sistemas - Aula005Clá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 - Controlando a Concorrência em Aplicações Multi-Thread
Delphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-ThreadDelphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-Thread
Delphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-ThreadMario Guedes
 
Delphi Conference 2011 - Integração Contínua
Delphi Conference 2011 - Integração ContínuaDelphi Conference 2011 - Integração Contínua
Delphi Conference 2011 - Integração ContínuaJosé Araújo
 

Andere mochten auch (20)

Oo delphi
Oo delphiOo delphi
Oo delphi
 
Programação orientada a objetos em delphi
Programação orientada a objetos em delphiProgramação orientada a objetos em delphi
Programação orientada a objetos em delphi
 
Linguagem Delphi-Introdução
Linguagem Delphi-IntroduçãoLinguagem Delphi-Introdução
Linguagem Delphi-Introdução
 
Git & Delphi
Git & DelphiGit & Delphi
Git & Delphi
 
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
 
FireDAC - Embarcadero Conference 2015
FireDAC - Embarcadero Conference 2015FireDAC - Embarcadero Conference 2015
FireDAC - Embarcadero Conference 2015
 
Aplicativo aula006
Aplicativo aula006Aplicativo aula006
Aplicativo aula006
 
Sistema Operacional - Pratica002
Sistema Operacional - Pratica002Sistema Operacional - Pratica002
Sistema Operacional - Pratica002
 
Sistema Operacional - Pratica003
Sistema Operacional - Pratica003Sistema Operacional - Pratica003
Sistema Operacional - Pratica003
 
Projeto de Sistemas - Aula005
Projeto de Sistemas - Aula005Projeto de Sistemas - Aula005
Projeto de Sistemas - Aula005
 
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 - Controlando a Concorrência em Aplicações Multi-Thread
Delphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-ThreadDelphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-Thread
Delphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-Thread
 
Delphi Conference 2011 - Integração Contínua
Delphi Conference 2011 - Integração ContínuaDelphi Conference 2011 - Integração Contínua
Delphi Conference 2011 - Integração Contínua
 

Ähnlich wie Orientação a Objetos no Delphi - Controle de Estoque (III)

Treinamento Básico Sobre ASP.NET MVC
Treinamento Básico Sobre ASP.NET MVCTreinamento Básico Sobre ASP.NET MVC
Treinamento Básico Sobre ASP.NET MVCMichael Costa
 
programacao-c-banco-de-dados
programacao-c-banco-de-dadosprogramacao-c-banco-de-dados
programacao-c-banco-de-dadosRaul Dias
 
hibernate annotation
hibernate annotationhibernate annotation
hibernate annotationeduardo dias
 
Entendendo a Tríade Model-View-Controller (MVC) Utilizando Padrões de Projeto...
Entendendo a Tríade Model-View-Controller (MVC) Utilizando Padrões de Projeto...Entendendo a Tríade Model-View-Controller (MVC) Utilizando Padrões de Projeto...
Entendendo a Tríade Model-View-Controller (MVC) Utilizando Padrões de Projeto...Lucas Furtado de Oliveira
 
Apostila PhP com Wamp, 4a Parte
Apostila PhP com Wamp, 4a ParteApostila PhP com Wamp, 4a Parte
Apostila PhP com Wamp, 4a ParteIlton Barbosa
 
Metodologia de desenvolvimento de sistemas
Metodologia  de desenvolvimento de sistemasMetodologia  de desenvolvimento de sistemas
Metodologia de desenvolvimento de sistemasPriscila Stuani
 
Como criar interfaces gráficas com android
Como criar interfaces gráficas com androidComo criar interfaces gráficas com android
Como criar interfaces gráficas com androidRicardo Ogliari
 
Apostila ph pwamp_parte5
Apostila ph pwamp_parte5Apostila ph pwamp_parte5
Apostila ph pwamp_parte5Ilton Barbosa
 
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
 
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
 
Framework Entities na CBSoft
Framework Entities na CBSoftFramework Entities na CBSoft
Framework Entities na CBSoftMarcius Brandão
 
Observable Binding Para Atualização na UI Android
Observable Binding Para Atualização na UI AndroidObservable Binding Para Atualização na UI Android
Observable Binding Para Atualização na UI AndroidVinícius Thiengo
 

Ähnlich wie Orientação a Objetos no Delphi - Controle de Estoque (III) (20)

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
 
Oficina cake php
Oficina cake phpOficina cake php
Oficina cake php
 
Apostila Android
Apostila AndroidApostila Android
Apostila Android
 
Treinamento Básico Sobre ASP.NET MVC
Treinamento Básico Sobre ASP.NET MVCTreinamento Básico Sobre ASP.NET MVC
Treinamento Básico Sobre ASP.NET MVC
 
programacao-c-banco-de-dados
programacao-c-banco-de-dadosprogramacao-c-banco-de-dados
programacao-c-banco-de-dados
 
Framework Miolo
Framework MioloFramework Miolo
Framework Miolo
 
hibernate annotation
hibernate annotationhibernate annotation
hibernate annotation
 
Entendendo a Tríade Model-View-Controller (MVC) Utilizando Padrões de Projeto...
Entendendo a Tríade Model-View-Controller (MVC) Utilizando Padrões de Projeto...Entendendo a Tríade Model-View-Controller (MVC) Utilizando Padrões de Projeto...
Entendendo a Tríade Model-View-Controller (MVC) Utilizando Padrões de Projeto...
 
Tutorial struts
Tutorial strutsTutorial struts
Tutorial struts
 
Aula1
Aula1Aula1
Aula1
 
Apostila PhP com Wamp, 4a Parte
Apostila PhP com Wamp, 4a ParteApostila PhP com Wamp, 4a Parte
Apostila PhP com Wamp, 4a Parte
 
Metodologia de desenvolvimento de sistemas
Metodologia  de desenvolvimento de sistemasMetodologia  de desenvolvimento de sistemas
Metodologia de desenvolvimento de sistemas
 
Como criar interfaces gráficas com android
Como criar interfaces gráficas com androidComo criar interfaces gráficas com android
Como criar interfaces gráficas com android
 
Apostila ph pwamp_parte5
Apostila ph pwamp_parte5Apostila ph pwamp_parte5
Apostila ph pwamp_parte5
 
CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
CURSO DELPHI FUND. CLIENT SERVER (DIURNO) CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
 
Artigo c#
Artigo c#Artigo c#
Artigo c#
 
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
 
Framework Entities na CBSoft
Framework Entities na CBSoftFramework Entities na CBSoft
Framework Entities na CBSoft
 
Observable Binding Para Atualização na UI Android
Observable Binding Para Atualização na UI AndroidObservable Binding Para Atualização na UI Android
Observable Binding Para Atualização na UI Android
 
Asp net mvc
Asp net mvcAsp net mvc
Asp net mvc
 

Mehr von 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
 

Mehr von 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 (III)

  • 1. Orientação a Objetos no Delphi: Controle de Estoque – Parte Final Ryan Bruno C Padilha ryan.padilha@gmail.com http://ryanpadilha.com.br Objetivo deste artigo Este artigo é a parte final de uma série de três artigos onde abordamos o paradigma orientado a objetos. No segundo artigo iniciamos a construção de uma aplicação de controle de estoque básico, provando na prática que a OO não possui estruturas complexas de dados; ao contrário, contempla um modelo simplificado de um conjunto de classes que se relacionam entre si, seja através de heranças ou associações de agregação/composição. Nesta terceira parte será revisto o modelo de domínio do controle de estoque, reforçando a utilização da notação UML, que oferece uma documentação padronizada e simplificada do projeto de software. A implementação em Object Pascal do restante das classes de domínio é realizado com base na documentação referida acima, porém o objetivo agora é definir o comportamento dos objetos de negócio instanciados na memória principal sobre a camada de visualização de dados (view/formulário), exibindo a forma como operam com os campos do formulário e como podem ser invocados por outro formulário. 1. Revisão do Modelo Conceitual O modelo de domínio abordado é o controle de estoque, do qual tem por finalidade em síntese otimizar o investimento em estoques, minimizando a necessidade de capital investido. Nos artigos anteriores discutimos e implementamos parte do diagrama de classes exibido na figura 1, ou seja, na segunda parte desta série implementamos no ambiente Delphi as classes: Endereco, Pessoa, PessoaJ e Empresa; e construímos o formulário principal da aplicação, bem como o formulário de cadastro do grupo de empresas (view). Com o referido cadastro em funcionamento podemos cadastrar as empresas que terão controle sobre seus estoques de produtos, realizando a entrada e saída dos mesmos seja através do formulário de manutenção de estoque ou mesmo pela entrada de notas fiscais e/ou pela operação de venda ao consumidor final (estes dois últimos itens citados não fazem parte do escopo do artigo, foram apenas citados por realizarem operações sobre a quantidade de produtos em estoque). O propósito agora é implementar as classes: Marca, Unidade, Produto e Estoque; as demais classes Categoria, Pedido e Entrada não serão implementadas neste momento para não fugirmos demasiadamente do objetivo do artigo e para simplificar a implementação. Conforme citado no segundo artigo, uma boa ferramenta para realizar a modelagem de classes, é o software Jude Community (encontrado em http://jude.change-vision.com/jude- web/product/community.html), porém infelizmente o projeto desta ferramenta de modelagem foi descontinuado pela empresa ChangeVision que a mantinha. Os leitores que tiveram o interesse em baixar a ferramenta e ver como a mesma funciona ficaram frustrados. Mas nem tudo está perdido, como é de costume a comunidade de desenvolvedores reivindicou pela ferramenta de modelagem UML e a empresa mantenedora do projeto retomou este projeto renomeando-o como Astah*Community, que pode ser encontrado em http://astah.change-vision.com/en/product/astah-community.html.
  • 2. A ferramenta Astah*Community é gratuita, suporta notação UML 2.0, suprindo a necessidade de grande parte dos elementos necessários no dia-a-dia. O diagrama de classes da figura 1, foi modelado utilizando o Astah* versão 6.4, caso queira baixar o arquivo do diagrama de classes do modelo conceitual de controle de estoque, o mesmo pode ser encontrado em http://ryanpadilha.com.br/downloads/active_delphi/UML_controle_estoque.jude. Seria interessante baixar o diagrama citado, aprender a utilizar a ferramenta, assim como identificar os elementos básicos de um diagrama de classe, pois para os leitores que acompanham os artigos do colunista que os escreve, futuramente abordaremos outros conceitos referentes a arquitetura e engenharia de software utilizando como base o modelo acima. É válido observar no diagrama que o elemento Estoque tem sua definição completa, com seus atributos e métodos. Implementar em Object Pascal esta classe e sua respectiva interação com um formulário visual é mais trabalhoso, pois se trata de uma operação de movimentação, frente a implementação de classes de negócios que efetuam apenas operações simples de CRUD (acrônimo de Create, Retrieve, Update, Delete) como foi abordado na definição dos elementos Empresa e Endereco. 1.1 O Contexto da classe Estoque A classe Estoque está associada a classe Empresa, pois uma empresa pode possuir vários produtos em estoque do qual queira controlar e manter um histórico de entrada e saída do mesmo. Uma aplicação de controle de estoque pode controlar o estoque de várias empresas, por isso implementamos um cadastro de grupo de empresas, para que possamos cadastrar as empresas que controlarão seus estoques. A cardinalidade entre Empresa e Estoque é de 1..* (um para vários), ou seja, cada empresa controla apenas um único estoque (individualmente), que é constituído por vários produtos, porém o estoque controlado por cada empresa pode ter um saldo diferente de um mesmo produto, sendo que há uma separação lógica do mesmo dentro do banco de dados. Em relação a classe Produto, esta se relaciona com a classe Estoque através da associação com cardinalidade 1..* (um para vários), onde para um determinado produto há a ocorrência de vários registros em um estoque, e o mesmo possui apenas uma referência ao produto. Resumidamente encontramos um produto com identificação única (através do ID) dentro de um estoque definindo o tipo de movimentação (E/S) e a quantidade informada pelo usuário da aplicação. Esta definição ficará mais clara até o final do artigo. O elemento Produto está associado também a um elemento Marca, cardinalidade de *..1, um produto tem uma única marca e uma marca pode pertencer a vários produtos; e pode conter várias medidas de Unidade, cardinalidade de *..*, um produto pode conter várias unidades de medida e as unidades de medidas pertencem a vários produtos. Vejamos em mais detalhes o que a classe Estoque possui em sua definição, detalhando as assinaturas dos métodos implementados: 1) public Validar(): boolean – efetua a validação do estado do objeto instanciado em memória, tornando-o consistente; 2) public Movimentacao(): boolean – a movimentação de entrada e saída de produtos de uma determinada empresa no estoque é realizado através da implementação deste método, que é também o principal método da classe; public ConsultarSaldo(): Double – consulta e retorna o saldo atual de um produto pertencente ao estoque de determinada empresa (saldo entrada – saldo saída); public
  • 3. getObject(Id: String): boolean – retorna a movimentação do estoque de um produto através de seu ID (código); public getObjects(): boolean – toda a movimentação efetuada no estoque de uma empresa é retornado; public getObjects(Id: String): boolean – através deste método é exibido na Grid do formulário visual (FrmControleEstoque) o histórico de movimentação de um produto especificado pelo argumento ID (código). Figura 1 – Diagrama de Classe Simplificado. Domínio: Controle de Estoque. 2. Objetos de negócio e formulários: Divisão de responsabilidades em duas camadas 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. Adotando o exemplo criado anteriormente na segunda parte da série, continuaremos a implementar o aplicação de controle de estoque. Para quem irá começar a acompanhar o desenvolvimento da aplicação deste ponto, o código-fonte de exemplo pode ser encontrado em http://activedelphi.com.br/downloads/orientacao_objetos.rar. A IDE Delphi 7 Update2 está sendo utilizado no desenvolvimento, pois o objetivo desta série sobre Orientação a Objetos e seus conceitos adjacentes está voltado a implementação do modelo conceitual e não focado na utilização de componentes específicos de software. Para realizar a persistência de dados estamos utilizando o SGBD objeto-relacional PostgreSQL 8.3, que pode ser encontrado em http://www.postgresql.org.
  • 4. Com o Delphi aberto, procure pelo projeto “ControleEstoque”, que foi salvo anteriormente no diretório “d:projetosoocontrole_estoque” (ou no diretório de sua preferência), abra-o e o mesmo será exibido dentro da IDE. O menu principal da aplicação fora definido anteriormente, restando apenas criar os formulários dos itens de menu. Iremos implementar apenas o formulário de Cadastro de Produto e o de Movimentação de Estoque, ficando a criação do restante dos cadastros sugeridos a critério do leitor, pois ao termino deste artigo todos os princípios básicos de construção de formulários e sua interação com objetos de negócios (classes) definidos no escopo da aplicação serão abordados. 2.1 Classes de negócio Seguindo a mesma linha de desenvolvimento, comecemos com a implementação das classes de negócio, mais especificamente com a classe concreta Unidade; a responsabilidade dessa classe é conter dados relacionados com as unidades de medidas utilizadas pelos produtos. Adicione uma nova unit ao projeto através do Menu File – New – Unit, salve-a no diretório “classes” como clUnidade.pas. No bloco interface/implementation da unit declare/implemente a classe conforme abaixo: unit clUnidade; interface type TUnidade = class(TObject) private // métodos privados // métodos acessores suprimidos. getters / setters. function Insert(): Boolean; function Update(): Boolean; protected // declaração de atributos _codigo: String; _descricao: String; _sigla: String; public // declaração das propriedades da classe, encapsulamento de atributos property Codigo: String read getCodigo write setCodigo; property Descricao: String read getDescricao write setDescricao; property Sigla: String read getSigla write setSigla; // declaração de métodos públicos function Validar(): Boolean; function Merge(): Boolean; function Delete(): Boolean; function getObject(Id: String): Boolean; function getObjects(): Boolean; function getField(campo: String; coluna: String): String; end; const TABLENAME = 'UNIDADE';
  • 5. implementation uses clUtil, dmConexao, SysUtils, Dialogs; { TUnidade } // implementação suprimida, para não estender muito o artigo end. Depois da definição e implementação da classe acima, precisamos agora implementar a classe Marca que é responsável por conter dados relacionados as marcas dos produtos comercializados por uma empresa do ramo atacadista/varejista. Adicione uma nova unit ao projeto através do Menu File – New – Unit, salve-a no diretório “classes” como clMarca.pas. No bloco interface da unit declare a classe conforme abaixo: unit clMarca; interface type TMarca = class(TObject) private // métodos privados // métodos acessores suprimidos. getters / setters. function Insert(): Boolean; function Update(): Boolean; protected // declaração de atributos _codigo: String; _descricao: String; public // declaração das propriedades da classe, encapsulamento de atributos property Codigo: String read getCodigo write setCodigo; property Descricao: String read getDescricao write setDescricao; // declaração de métodos públicos function Validar(): Boolean; function Merge(): Boolean; function Delete(): Boolean; function getObject(Id: String): Boolean; function getObjects(): Boolean; function getField(campo: String; coluna: String): String; end; const TABLENAME = 'MARCA'; implementation uses clUtil, dmConexao, SysUtils, Dialogs;
  • 6. { TMarca } // implementação suprimida, para não estender muito o artigo end. Implementamos as classes Unidade e Marca a princípio pois as mesmas estão associadas com a classe Produto. Na notação UML identificada na figura 1, esta associação possui a definição de navegabilidade, ou seja, a classe Produto contém referência a objetos do tipo Unidade e Marca. Logo abaixo na implementação da classe Produto será possível visualizar atributos declarados com os tipos definidos por nós, e no método construtor da classe a responsabilidade em instanciar os objetos referenciados. É denotado aqui a interação entre os objetos de negócio, compondo um rico ambiente onde as diversas unidades de software (objetos), que inter-relacionadas formam o escopo de uma aplicação, definindo a divisão de responsabilidades em classes de negócios, resultando em uma coesão satisfatória e uma granularidade razoável. Adicione uma nova unit ao projeto através do Menu File – New – Unit, salve-a no diretório “classes” como clProduto.pas. Nesta unit declaramos a classe conforme abaixo: unit clProduto; interface // utilização das units declaradas anteriormente, classes de negócios uses clUnidade, clMarca; type TProduto = class(TObject) private // métodos privados // métodos acessores suprimidos. getters / setters. function Insert(): Boolean; function Update(): Boolean; protected // declaração de atributos _codigo: String; _codigoPrincipal: String; _descricao: String; _descReduzido: String; _status: Boolean; _unidade: TUnidade; // _marca: TMarca; // // categoria... public // método construtor definido por nós constructor Create; // declaração das propriedades da classe, encapsulamento de atributos property Codigo: String read getCodigo write setCodigo; property CodigoPrincipal: String read getCodigoPrinc write setCodigoPrinc; property Descricao: String read getDescricao write setDescricao;
  • 7. property DescReduzido: String read getDescReduzido write setDescReduzido; property Status: Boolean read getStatus write setStatus; property Unidade: TUnidade read getUnidade write setUnidade; property Marca: TMarca read getMarca write setMarca; // na linha acima antes do ponto e virgula (setStatus) pressione Ctrl + Shift + C // para gerar os métodos acessores getter e setter automaticamente // declaração de métodos públicos function Validar(): Boolean; function Merge(): Boolean; function Delete(): Boolean; function getObject(Id: String): Boolean; function getObjects(): Boolean; function getField(campo: String; coluna: String): String; end; const TABLENAME = 'PRODUTO'; implementation uses clUtil, dmConexao, SysUtils, Dialogs; { TProduto } // método construtor constructor TProduto.Create; begin _unidade := TUnidade.Create; // instanciação do objeto Unidade _marca := TMarca.Create; // instanciação do objeto Marca end; // implementação suprimida, para não estender muito o artigo end. Através desta série de artigos sobre orientação a objetos no Delphi, adotamos como exemplo prático o desenvolvimento de uma aplicação de controle de estoque com o intuito de contemplar a maioria dos conceitos apresentados teoricamente na primeira parte da série. E neste momento será definido a classe principal de nosso projeto, ou seja, a classe Estoque que é responsável por controlar o estoque dos produtos de uma determinada empresa através das operações de entrada e saída. Visualizando a modelagem da figura 1, fica claro que o elemento Estoque está no cerne do diagrama de classes, pois está relacionado com a classe Produto e Empresa, que conseqüentemente tem uma rica interação com outros elementos do escopo. É interessante comentar sobre a associação e navegabilidade entre a classe Estoque-Produto e Estoque-Empresa, onde em um estoque efetuamos operações de entrada/saída de produtos definindo a quantidade e valor de custo do mesmo, sobre o estoque de uma determinada empresa em particular. A descrição sobre a navegabilidade pode ser sintetizada através da notação de cardinalidade citado logo no início deste artigo.
  • 8. Adicione uma nova unit ao projeto através do Menu File – New – Unit, salve-a no diretório “classes” como clEstoque.pas. Como esta classe de negócio é o foco principal da aplicação, será apresentado o código-fonte completo da mesma (exceto os métodos acessores – get/set). Nesta unit declaramos a classe conforme abaixo: unit clEstoque; interface // utilização das units declaradas anteriormente, classes de negócios uses clProduto, clEmpresa; type TEstoque = class(TObject) private // métodos privados // métodos acessores suprimidos. getters / setters. protected // declaração de atributos _codigo: String; _data: TDateTime; _hora: TDateTime; _documento: String; _saldo: Double; _vlrCusto: Currency; _tipoMov: String; _quantidade: Double; _flag: Boolean; _produto: TProduto; _empresa: TEmpresa; public // método construtor definido por nós constructor create; // declaração das propriedades da classe, encapsulamento de atributos property Codigo: String read getCodigo write setCodigo; property Data: TDateTime read getData write setData; property Hora: TDateTime read getHora write setHora; property Documento: String read getDocumento write setDocumento; property Saldo: Double read getSaldo write setSaldo; property VlrCusto: Currency read getVlrCusto write setVlrCusto; property TipoMov: String read getTipoMov write setTipoMov; property Quantidade: Double read getQuantidade write setQuantidade; property Flag: Boolean read getFlag write setFlag; property Produto: TProduto read getProduto write setProduto; property Empresa: TEmpresa read getEmpresa write setEmpresa; // declaração de métodos públicos function Validar(): Boolean; function Movimentacao(): Boolean; function ConsultarSaldo(): Double; function getObject(Id: String): Boolean;
  • 9. function getObjects: Boolean; overload; function getObjects(Id: String): Boolean; overload; end; const TABLENAME = 'ESTOQUE'; implementation uses SysUtils, dmConexao, Dialogs, clUtil, DB, ZAbstractRODataset; { TEstoque } // método construtor constructor TEstoque.create; begin _produto := TProduto.Create; // instanciação do objeto Produto _empresa := TEmpresa.Create; // instanciação do objeto Empresa end; // implementação suprimida dos métodos acessores (get/set), para não estender muito o artigo // todos os métodos contendo regras de negócios estão relacionados abaixo function TEstoque.ConsultarSaldo(): Double; begin Try Result := 0; with Conexao.QryGetObject do begin Close; SQL.Clear; SQL.Text := 'SELECT SUM(EST_QUANTIDADE) - COALESCE((SELECT SUM(EST_QUANTIDADE) AS EST_SALDO FROM '+ TABLENAME + ' WHERE PRO_CODIGO =:PRODUTO AND EMP_CODIGO =:EMPRESA AND EST_TIPO_MOV = '''+'S'+'''), 0) AS EST_SALDO '+ ' FROM '+ TABLENAME + ' WHERE PRO_CODIGO =:PRODUTO AND EMP_CODIGO =:EMPRESA AND EST_TIPO_MOV = '''+'E'+''' '; ParamByName('PRODUTO').AsString := Self.Produto.Codigo; ParamByName('EMPRESA').AsString := Self.Empresa.Codigo; Open; First; end; if Conexao.QryGetObject.RecordCount > 0 then Result := Conexao.QryGetObject.FieldByName('EST_SALDO').AsFloat; Except on E : Exception do ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message); end; end; function TEstoque.Movimentacao: Boolean; begin // Movimentação de Estoque
  • 10. Try Result := False; with Conexao.QryCRUD do begin Close; SQL.Clear; SQL.Text := 'INSERT INTO '+ TABLENAME +' (PRO_CODIGO, EMP_CODIGO, EST_DATA, EST_HORA, EST_DOCUMENTO, EST_SALDO, '+ ' EST_VLR_CUSTO, EST_TIPO_MOV, EST_QUANTIDADE) '+ ' VALUES (:PRODUTO, :EMPRESA, :DATA, :HORA, :DOCUMENTO, :SALDO, :VLR_CUSTO, :TIPO_MOV, :QUANTIDADE)'; ParamByName('PRODUTO').AsString := Self.Produto.Codigo; ParamByName('EMPRESA').AsString := Self.Empresa.Codigo; ParamByName('DATA').AsDateTime := Self.Data; ParamByName('HORA').AsDateTime := Now; // hora atual ParamByName('DOCUMENTO').AsString := Self.Documento; // verificando o tipo de movimento if Self.TipoMov = 'E' then ParamByName('SALDO').AsFloat := (Self.ConsultarSaldo + Self.Quantidade) else ParamByName('SALDO').AsFloat := (Self.ConsultarSaldo - Self.Quantidade); ParamByName('VLR_CUSTO').AsCurrency := Self.VlrCusto; ParamByName('TIPO_MOV').AsString := Self.TipoMov; ParamByName('QUANTIDADE').AsFloat := Self.Quantidade; ExecSQL; end; Result := True; Except on E : Exception do ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message); end; end; function TEstoque.getObjects: Boolean; begin Try Result := False; with Conexao.QryGetObject do begin Close; SQL.Clear; SQL.Text := 'SELECT * FROM '+ TABLENAME +' ORDER BY EST_CODIGO'; Open; First; end; if Conexao.QryGetObject.RecordCount > 0 then Result := True; Except on E : Exception do ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message);
  • 11. end; end; // pegar movimentação de estoque pelo ID (PRODUTO) function TEstoque.getObject(Id: String): Boolean; begin try Result := False; if TUtil.Empty(Id) then Exit; with Conexao.QryGetObject do begin Close; SQL.Clear; SQL.Text := 'SELECT * FROM '+ TABLENAME +' WHERE PRO_CODIGO =:CODIGO AND EMP_CODIGO =:EMPRESA'; ParamByName('CODIGO').AsString := Id; ParamByName('EMPRESA').AsString := Self.Empresa.Codigo; Open; First; end; if Conexao.QryGetObject.RecordCount > 0 then begin Self.Codigo := Conexao.QryGetObject.FieldByName('EST_CODIGO').AsString; Self.Produto.Codigo := Conexao.QryGetObject.FieldByName('PRO_CODIGO').AsString; Self.Data := Conexao.QryGetObject.FieldByName('EST_DATA').AsDateTime; Self.Hora := Conexao.QryGetObject.FieldByName('EST_HORA').AsDateTime; Self.Documento := Conexao.QryGetObject.FieldByName('EST_DOCUMENTO').AsString; Self.Saldo := Conexao.QryGetObject.FieldByName('EST_SALDO').AsFloat; Self.VlrCusto := Conexao.QryGetObject.FieldByName('EST_VLR_CUSTO').AsCurrency; Self.TipoMov := Conexao.QryGetObject.FieldByName('EST_TIPO_MOV').AsString; Self.Quantidade := Conexao.QryGetObject.FieldByName('EST_QUANTIDADE').AsFloat; Self.Flag := Conexao.QryGetObject.FieldByName('EST_FLAG').AsBoolean; Result := True; end; Except on E : Exception do ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message); end; end; function TEstoque.Validar: Boolean; begin // validação de atributos if Length(DateToStr(_data)) <> 10 then begin ShowMessage('Data Inválida!'); Result := false; Exit; end else if _quantidade = 0 then begin ShowMessage('Quantidade Inválida!'); Result := False; Exit; end;
  • 12. Result := True; end; function TEstoque.getObjects(Id: String): Boolean; begin Try Result := False; with Conexao.QryEstoque do begin Close; SQL.Clear; SQL.Text := 'SELECT * FROM '+ TABLENAME +' WHERE PRO_CODIGO =:CODIGO AND EMP_CODIGO =:EMPRESA ORDER BY EST_CODIGO'; ParamByName('CODIGO').AsString := Id; ParamByName('EMPRESA').AsString := Self.Empresa.Codigo; Open; First; end; if Conexao.QryGetObject.RecordCount > 0 then begin Self.getObject(Id); Result := True; end; Except on E : Exception do ShowMessage('Classe: '+ e.ClassName + chr(13) + 'Mensagem: '+ e.Message); end; end; end. Agora que temos o diagrama de classes representado pela figura 1 implementado totalmente em Object Pascal (exceto a classe Categoria), vamos construir o formulário que irá persistir os objetos do tipo Produto e outro que efetue o controle de estoque, através da movimentação de produtos operando a entrada e saída de produtos, atualizando seu saldo corrente. 2.2 A camada de visualização de dados: O formulário Utilizando o conceito RAD (Rapid Application Development - Desenvolvimento Rápido de Aplicativos) da IDE Delphi construímos formulários visuais com rapidez e facilidade, obtemos uma velocidade ainda maior no desenvolvimento pois a implementação de toda a lógica da aplicação já está definida. Com isso os formulários passam a atuar definitivamente apenas como instrumentos de entrada e visualização de dados, tendo sua responsabilidade resumida a isto. Não é necessário especificar todos os componentes visuais e suas respectivas propriedades, estou assumindo que a maioria dos leitores possui plenos conhecimentos em construção de formulários visuais utilizando o Delphi. Para a construção do formulário de Cadastro de Produtos tomemos como base o layout sugerido pela figura 2. E para o formulário principal da aplicação, o de Controle de Estoque adotemos o layout proposto pela figura 3.
  • 13. Figura 2 – Formulário de Cadastro de Produto. No formulário da figura 2, podemos utilizar a classe Produto declarando uma variável do tipo TProduto no bloco interface/var da unit. Todos os dados digitados no formulário são atribuídos as propriedades da classe Produto, alterando o estado do objeto instanciado, que é então persistido no SGBD. Toda a interação efetuada com o formulário ocorre através de eventos, que quando disparados executam algum procedimento dentro da aplicação. Para exemplificar o que acabados de descrever, ao clicarmos sobre o botão Salvar (ícone disquete), é invocado o evento onClick sppSalvarClick(Sender: TObject) que contempla a seguinte declaração: procedure TFrmCadastroProduto.sppSalvarClick(Sender: TObject); var Operacao: String; begin Operacao := 'U'; // atribuindo os valores digitados no formulário as propriedades do objeto Produto Produto.Codigo := edtCodigo.Text; Produto.CodigoPrincipal := edtCodigoPrinc.Text; Produto.Descricao := edtDescricao.Text; Produto.DescReduzido := edtDescRed.Text; if cmbStatus.ItemIndex = 0 then Produto.Status := false else Produto.Status := true; if TUtil.Empty(Produto.Codigo) then Operacao := 'I';
  • 14. if Produto.Validar() then if Produto.Merge() then begin if Operacao = 'I' then ShowMessage('Registro Gravado com Sucesso!') else ShowMessage('Registro Atualizado com Sucesso!'); Conexao.QryProduto.Close; Conexao.QryProduto.Open; sppCancelarClick(Self); end; end; Antes mesmo da chamada do método Merge() que é responsável por persistir o objeto no banco de dados, as propriedades do objeto são alteradas através da atribuição dos valores digitados no formulário. Notamos que o formulário apenas “repassa” os valores ao objeto e o mesmo se encarrega de validar e persistir os dados efetivamente. O que acabamos de descrever aqui é um modelo de divisão de responsabilidade onde cada unidade de software é responsável por determinada atividade. Temos mais dois eventos declarados no formulário da figura 2 que serão abordados – o procedimento privado onClick sppCancelarClick(Sender: TObject) que limpa os campos do formulário, destrói e instancia novamente o objeto do tipo Produto, renovando seu estado. Quando clicamos no botão cancelar (ícone X), o seguinte procedimento é executado: procedure TFrmCadastroProduto.sppCancelarClick(Sender: TObject); begin TUtil.LimparFields(FrmCadastroProduto); Produto := nil; Produto := TProduto.Create; edtDescricao.SetFocus; end; O segundo evento citado no parágrafo acima é o procedimento onClick sppExcluirClick(Sender: TObject) que deleta um objeto Produto da tabela relacional se a propriedade código do objeto instanciado em memória estiver com valor definido e for consistente. Quando clicamos no botão excluir (ícone lixeira), o seguinte evento é disparado: procedure TFrmCadastroProduto.sppExcluirClick(Sender: TObject); begin if TUtil.Empty(Produto.Codigo) then Exit; if MessageBox(Application.Handle, 'Deseja Realmente Excluir o Registro?', 'Controle Estoque', MB_ICONQUESTION + MB_YESNO + MB_DEFBUTTON2) = ID_NO then Exit; if TUtil.NotEmpty(Produto.Codigo) then begin if NOT Produto.Delete then ShowMessage('Erro ao Excluir o Registro.') else begin TUtil.LimparFields(FrmCadastroProduto);
  • 15. Conexao.QryProduto.Close; Conexao.QryProduto.Open; end; end; end; Com o cadastro de produto em pleno funcionamento podemos realizar operações CRUD com o mesmo, necessitando a princípio inserir produtos que serão controlados pelo formulário da figura 3, o controle de estoque. Neste formulário selecionamos a empresa da qual estamos controlando o estoque de produtos, cada empresa possui um estoque independente conforme citado anteriormente. No campo “Código do Produto” digitamos o código do produto do qual queiramos pesquisar e visualizar o histórico de movimentação de entrada e saída, assim como seu saldo atual em estoque. Após um produto ser encontrado, seu estado é recuperado do banco de dados e definido na instancia do objeto em memória (objeto Estoque.Produto), o componente visual groupBox de movimentação é exibido, permitindo a movimentação de Entrada(1) ou Saída(2) do produto – informando uma quantidade (número de ponto flutuante positivo), valor monetário de custo (compra), número do documento do qual origina-se o movimento. Ao clicar no tipo de movimento (componente radioGroup) o botão movimentar é ativado e sua propriedade caption é modificada de acordo com o tipo selecionado. Ao clicar no referido botão o seguinte evento é disparado: procedure TFrmControleEstoque.btnMovimentarClick(Sender: TObject); begin if MessageBox(Application.Handle, 'Deseja Realmente Movimentar o Estoque?', 'Controle Estoque', MB_ICONQUESTION + MB_YESNO + MB_DEFBUTTON2) = ID_NO then Exit; case rdgTipo.ItemIndex of 0 : Estoque.TipoMov := 'E'; // entrada 1 : Estoque.TipoMov := 'S'; // saída end; // alterando o estado do objeto Estoque Estoque.Data := StrToDate(mskData.Text); Estoque.Quantidade := StrToFloat(edtQuantidade.Text); Estoque.VlrCusto := StrToFloat(edtValorCusto.Text); Estoque.Documento := edtDocumento.Text; if Estoque.Validar() then if Estoque.Movimentacao() then LimparMovimento else ShowMessage('Problemas ao Efeturar Movimentação no Estoque!'); end;
  • 16. Figura 3 – Formulário de Controle de Estoque (movimentação). O método Movimentacao(): boolean é o principal método definido no escopo da aplicação, executando a movimentação de estoque, atualizando o saldo em estoque do produto selecionado. Caso tenha alguma dúvida em como a regra está implementada na classe clEstoque.pas verifique novamente a declaração do código da classe definida anteriormente. O formulário da figura 3 pode ser invocado também através do cadastro de produtos, clicando no botão “Verificar Estoque”; se algum produto estivar selecionado, ou seja, sendo visualizado no cadastro de produto, o mesmo será passado por referência ao objeto declarado como public ProdutoRef na unit do formulário de controle de estoque. O evento onClick do botão citado é definido na unit untCadastroProduto.pas como: procedure TFrmCadastroProduto.btnEstoqueClick(Sender: TObject); begin if NOT Assigned(FrmControleEstoque) then FrmControleEstoque := TFrmControleEstoque.Create(Application); // passando o Objeto Produto para o outro formulário (estoque) // em cada formulário encontramos um objeto do tipo produto // sendo possível passar o estado de um objeto de um formulário // ao objeto de outro formulário if TUtil.NotEmpty(Produto.Codigo) then FrmControleEstoque.ProdutoRef := Produto; FrmControleEstoque.ShowModal; end;
  • 17. O processo de transferir o estado de um objeto instanciado em um formulário a outro é comumente utilizado e de simples utilização. Este procedimento é utilizado também em formulários de pesquisa, que geralmente são invocados por formulários de cadastro. Na segunda parte da série criamos o banco de dados “ActiveDelphi” através da ferramenta gráfica pgAdminIII (acompanha a instalação do SGBD PostgreSQL), execute-a, com ela aberta dê dois cliques no hostname onde o banco de dados fora criado, realize o login, forneça apenas a senha que foi definida ao usuário do banco. No item Banco de Dados, expanda a lista de bancos de dados existentes e procure pelo nome “ActiveDelphi”, selecione-o; através do editor SQL (clicando no ícone SQL) execute o seguinte script SQL DDL (Data Definition Language): -- MARCA CREATE TABLE MARCA( MAR_CODIGO SERIAL NOT NULL, MAR_DESCRICAO VARCHAR(100) NOT NULL ); ALTER TABLE MARCA ADD CONSTRAINT PK_MARCA PRIMARY KEY(MAR_CODIGO); -- POPULANDO A TABELA MARCA INSERT INTO MARCA (MAR_DESCRICAO) VALUES ('DUREX'); INSERT INTO MARCA (MAR_DESCRICAO) VALUES ('EATON'); INSERT INTO MARCA (MAR_DESCRICAO) VALUES ('INDISA'); INSERT INTO MARCA (MAR_DESCRICAO) VALUES ('LUCIFLEX'); INSERT INTO MARCA (MAR_DESCRICAO) VALUES ('PERKINS'); INSERT INTO MARCA (MAR_DESCRICAO) VALUES ('STAHL'); -- UNIDADE CREATE TABLE UNIDADE( UND_CODIGO SERIAL NOT NULL, UND_DESCRICAO VARCHAR(100) NOT NULL, UND_SIGLA VARCHAR(5) UNIQUE NOT NULL ); ALTER TABLE UNIDADE ADD CONSTRAINT PK_UNIDADE PRIMARY KEY(UND_CODIGO); -- POPULANDO A TABELA UNIDADE INSERT INTO UNIDADE (UND_DESCRICAO, UND_SIGLA) VALUES ('CAIXA', 'CXA'); INSERT INTO UNIDADE (UND_DESCRICAO, UND_SIGLA) VALUES ('UNIDADE', 'UND'); INSERT INTO UNIDADE (UND_DESCRICAO, UND_SIGLA) VALUES ('KILO', 'KG'); INSERT INTO UNIDADE (UND_DESCRICAO, UND_SIGLA) VALUES ('METRO', 'MT'); -- PRODUTO CREATE TABLE PRODUTO( PRO_CODIGO SERIAL NOT NULL, PRO_C_PRINCIPAL VARCHAR(20), PRO_STATUS BOOLEAN, PRO_DESCRICAO VARCHAR(200),
  • 18. PRO_DESC_REDUZIDO VARCHAR(50), MAR_CODIGO INTEGER, UND_CODIGO INTEGER ); ALTER TABLE PRODUTO ADD CONSTRAINT PK_PRODUTO PRIMARY KEY(PRO_CODIGO); ALTER TABLE PRODUTO ADD CONSTRAINT FK_PRODUTO_MARCA FOREIGN KEY(MAR_CODIGO) REFERENCES MARCA(MAR_CODIGO); ALTER TABLE PRODUTO ADD CONSTRAINT FK_PRODUTO_UNIDADE FOREIGN KEY(UND_CODIGO) REFERENCES UNIDADE(UND_CODIGO); -- ESTOQUE CREATE TABLE ESTOQUE( EST_CODIGO SERIAL NOT NULL, PRO_CODIGO INTEGER NOT NULL, -- PRODUTO EMP_CODIGO INTEGER NOT NULL, -- EMPRESA EST_DATA DATE NOT NULL, EST_HORA TIME NOT NULL, EST_DOCUMENTO VARCHAR(20), EST_SALDO NUMERIC(15,5), EST_VLR_CUSTO NUMERIC(15,5), EST_TIPO_MOV CHAR, EST_QUANTIDADE NUMERIC(15,5), EST_FLAG BOOLEAN ); ALTER TABLE ESTOQUE ADD CONSTRAINT PK_ESTOQUE PRIMARY KEY(EST_CODIGO); ALTER TABLE ESTOQUE ADD CONSTRAINT FK_ESTOQUE_PRODUTO FOREIGN KEY(PRO_CODIGO) REFERENCES PRODUTO(PRO_CODIGO); ALTER TABLE ESTOQUE ADD CONSTRAINT FK_ESTOQUE_EMPRESA FOREIGN KEY(EMP_CODIGO) REFERENCES EMPRESA(EMP_CODIGO); Terminamos neste momento a aplicação de controle de estoque, que poderá ser baixada na integra em http://ryanpadilha.com.br/downloads/active_dephi/controle_estoque_parte2.rar. Caso algum leitor tenha alguma sugestão, crítica ou elogio referente ao que foi abordado e implementado aqui, entre em contato com este colunista que vos escreve. 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. 2.3 Justificativa da arquitetura em duas camadas Alguns leitores podem argumentar neste momento: Em aplicações que utilizam o paradigma estruturado, o formulário trata os dados digitados, não repassa informação a nenhum outro lugar, apenas persiste a informação em uma tabela relacional utilizando componentes de acesso direto a banco de dados (os famosos componentes DB<objeto>), a unit do formulário contem toda a lógica, resumindo é muito rápido desenvolver software assim. E com a arquitetura proposta neste artigo temos a divisão de responsabilidades em duas camadas
  • 19. (model e view), onde a implementação fica separada uma da outra e que no final da um pouco mais de trabalho em implementar. Afinal o que ganhamos com a utilização desse modelo de duas camadas ? Sinceramente este questionamento ocorre com freqüência, a maioria é feita por desenvolvedores originados do modelo estrutural de desenvolvimento. A orientação a objetos é uma evolução conceitual dentro do ramo da engenharia de software que vem se mostrando cada dia mais poderosa e flexível. Porém não é a palavra final tratando-se de desenvolvimento de software, com certeza a evolução caminha e novas tecnologias e conceitos surgem, complementando o modelo anteriormente proposto pelos pesquisadores e engenheiros de software. Retornando a pergunta provavelmente feita por muitos leitores, temos vários conceitos envolvidos neste modelo proposto: 1) O princípio de responsabilidade única (SRP – Single Responsability Principle) – onde cada classe ou até mesmo unit detêm responsabilidade exclusiva dentro do contexto da aplicação, aumentando significativamente a coesão das unidades de software; 2) Arquitetura de software em camadas – a manutenção do software que corresponde em média a 80% do investimento é facilitado pois temos divisão de implementação em camadas, reduzindo o acoplamento, ou seja, tornando as classes/units mais dependentes umas das outras; 3) Nível satisfatório de coesão e acoplamento – através da definição de classes coesas fica mais fácil de manter e estender suas funcionalidade assim como mantemos um conjunto de classes de regras de negócios que são auto-independentes da plataforma, ou seja, podemos ter as mesmas classes de negócios com apenas a camada de visualização (view) distintas – desktop ou intraweb, pois as temos um baixo acoplamento entre as camadas. 3. Conclusão Esta série de três partes sobre o paradigma orientado a objetos tem seu encerramento no fechamento deste artigo, do qual teve como objetivo revisar tudo o que fora visto até então sobre os conceitos teóricos e práticos e reforçar o que ainda não tinha sido abordado. Introduzimos o leitor no “mundo OO” exibindo suas vantagens e desvantagens, as dificuldades encontradas por programadores que desejam iniciar-se neste contexto e as tecnologias adjacentes que auxiliam o desenvolvedor a alcançar a qualidade de software. A teoria apresentada fora implementada na prática, comprovando que é possível sim desenvolver aplicativos robustos e flexíveis, orientados a objeto, utilizando o Object Pascal que é pouco difundido entre os desenvolvedores da comunidade Delphi, pois há uma carência de material de qualidade sobre o assunto. A aplicação de controle de estoque teve sua arquitetura definida em duas camadas (model/view), objetivando uma alta coesão e baixo acoplamento entre unidades de software, porém em uma medida satisfatória de granularidade. Este conceito de duas camadas pode ser substituída pelo padrão de projeto MVC (model/view/controller) melhorando o escopo de controle de estoque adotado. Em um próximo artigo veremos conceitualmente como este padrão de projeto opera e como pode ser implementado na prática sem maiores dificuldades.
  • 20. Fico contente e gratificado em ter ajudado os leitores a esclarecer suas dúvidas sobre orientação a objetos. A área de Engenharia de Software é ampla e contempla muitos conceitos e práticas das quais serão abordadas em outras oportunidades. Caso algum leitor tenha sugestões de artigos sobre a área citada entre em contato comigo. Será uma honra escrever novos artigos sobre arquitetura e engenharia. Caso tenha alguma dúvida entre em contato comigo. Será um prazer ajudar. Forte Abraço a todos os leitores que acompanharam a série Delphi OO – teórico e prático!