|
|
 |
| Tecnologias :: Visual FoxPro |
 |
|
| |
|
| Desenvolvimento de aplicações multi-camadas com VFP e VB |
Por Jorge A. Espinosa, artigo originalmente publicado na revista UTMag/RapoZine. |
Neste artigo poderemos ver como, utilizando as ferramentas que temos a nosso alcançe, poderemos fazer uso da tecnologia COM para encarar um desenvolvimento em n camadas e usufruir das verdadeiras vantagens da reutilização de código que nos permite a implementação da referida arquitetura. Desenvolveremos um sistema de teste no qual construiremos as camadas intermediárias e, sem necessidade trocar nenhum componente, faremos a mesma interface de usuário utilizando Visual Fox Pro e Visual Basic para depois tratar a origem de dados e ver a facilidade de alterar (neste caso pode ser outros como SQL Server, Oracle, etc) de uma origem de dados VFP para um BD do Access.
Como chegamos hoje a esta Tecnologia
Para compreender melhor onde estamos hoje ou que tecnologia estamos utilizando, devemos dar uma rápida olhada para trás e ver um pouco de história sobre o desenvolvimento de aplicações com base de dados
Quatro arquiteturas distintas de desenvolvimento se passaram até chegarmos hoje a conceber o denominado desenvolvimento em n camadas, mencionamos na primeira instância a primeira forma de escrever nossos programas que tivemos ao sentarmos pela primeira vez em frente a um PC (vocês lembram do FoxDOS ou Clipper ?), bom, aí temos a arquitetura de uma camada ou "Single-Tier", logo chegaram os servidores, começamos a trabalhar em 2 camadas ou Client/Server, Há alguns anos atrás, começamos a ouvir alguma coisa sobre desenvolvimento em 3 camadas (Three-Tier development), sobre isso, em particular, vamos entrar um pouco em detalhe, porque nos vai ser útil para entender a nova arquitetura
A idéia de desenvolvimento em 3 camadas consistia em utilizar um método de desenvolvimento para nossos sistemas que nos permitia separá-los em camadas distintas. As camadas recomendadas eram: A interface com o usuário, as regras de negócio e a base de dados, a idéia desta arquitetura estava baseada principalmente na capacidade de escabilidade que esta nos oferece, por exemplo, se temos desenvolvida uma aplicação baseada em uma fonte de dados em VFP e se no desenvolvimento desta, aplicamos apropriadamente as regras de criação de três camadas, quando quisermos que a mesma funcione, por exemplo com SQL Server, não deveríamos alterar mais do que a base de dados, a camada cliente ficaria intacta e, a camada de regras de negócios sofreria, talvez, uma alteração muito superficial. A figura abaixo nos mostra o conceito do funcionamento desta arquitetura.
Como podemos ver, esta arquitetura nos permite fazer que tanto a interface de usuário, as regras de negócios e a base de dados se converteram em entidades separadas umas das outras, o importante é manter bem definidas as interfaces e o que cada uma delas fazem para se comunicar com a outra.
Atualmente já nos encontramos falando em desenvolver aplicações em n camadas, a que temos de mais comum é a de quatro camadas, a camada adicionada é a que separa definitivamente as regras de negócio da de acesso a dados.
Esta arquitetura nos dá a vantagem de isolar definitivamente nossa lógica de negócios de tudo que tenha a ver com a origem de dados, já que desde o manejo da conexão até a execução de uma consulta manipulará a camada de acesso a dados. Deste modo, ante a qualquer eventual alteração, só se deverá tocar no módulo específico, assim como o momento de planejar a escabilidade de nosso sistema, se tivermos respeitado as regras básicas de projeto não deveríamos nos deparar com grandes modificações.
A importância desta arquitetura
Existem muitas razões para utilizar o desenvolvimento de aplicações em arquitetura de n camadas.
Abstração total sobre a origem dos dados As diferentes camadas se especializam absolutamente na função que devem fazer (processamento nas regras de negócio ou apresentação de dados na camada cliente) sem importar qual é a origem dos dados processados.
Baixo custo de desenvolvimento e manutenção das aplicações Se bem que no momento de projetar podemos observar uma carga maior de complexidade, a utilização desta arquitetura nos dá um controle maior de cada componente, assim como também a possibilidade de uma verdadeira reutilização do código. Por exemplo: Se tivéssemos em nossas regras de negócios uma função que nos mostre um resumo de conta de nossos clientes quando um usuário de nossa aplicação Win32, quando a camada cliente chamar este módulo executará a função MostrarListaConta() para ver o detalhe em seu monitor; mas se o desenvolvedor do site web da empresa no momento de montar a página de consulta nos pede isso, lhe diremos simplesmente que carregue o componente de regras de negócios e execute MostrarListaConta() Como podemos ver este é um exemplo concreto, já que mediante a utilização desta arquitetura, o desenvolvedor de uma interface de usuário jamais chegará a manipular diretamente um dado em nosso servidor a não ser através de um componente
Padronização das regras de negócio As regras de negócio se encontram encapsuladas em um set de rotinas comuns e podem ser chamadas de diversas aplicações sem necessidade de saber como esta funciona ou foi projetada Por exemplo: Suponhamos que uma das funções encapsuladas dentro de nossas regras de negócios se utilize para devolver os dados de um cliente. Nossa função DevolveCliente() aceitará como parâmetros o código do cliente e também processará nosso ID de usuário, então, depende de quem execute esta função será os dados que receberá como resposta. Se a execução for solicitada por um usário de baixo nível o retorno seria:
? DevuelveCliente("00002")
resultado :
Rodriguez, Alberto
Antibares 3372 6to C
Buenos Aires
Se for um usuário com um nível mais elevado poderia receber o seguinte:
? DevuelveCliente("00002")
resultado :
Rodriguez, Alberto
Antibares 3372 6to C
Buenos Aires
Saldo Conta : 120.00
Conta Inativa
Melhor qualidade nas aplicações Como as aplicações são construídas em unidades separadas, estas podem ser testadas independentemente e com muito mais precisão, isto permite obter um produto bem mais sólido
Reutilização de código A concepção natural de um sistema desenvolvido nesta arquitetura promove a reutilização de seus componentes em várias partes do próprio desenvolvimento e de futuros sistemas
Escabilidade Utilizando serviços como MTS muitos objetos podem escalar e ser distribuidos em um ambiente transacional de alta segurança
Os componentes
Antes de entrar em um desenvolvimento de um componente, primeiro devemos ter um conhecimento claro do que é isso.
Um componente é um objeto que pode instanciar, e como todo objeto, deve cumprir com as condições básicas do objeto (Abstração, Encapsulamento, Herança e Polimorfismo), deve ter muito bem definidos propriedades, métodos e eventos que vão expor e é muito importante destacar que estes devem funcionar livre de estado.
Bom, depois disto, deixamos um pouco de lado a teoria e ................. ao código!!
Para começar, planejei o desenvolvimento de um pequeno sistema que através de componentes acessa dados de um cliente e mostra os dados de sua conta tal como havíamos projetado anteriormente
Para seguir em frente este teste precisamos de uma tabela denominada CLIENTE com a seguinte estrutura:
| Campo | Tipo | Tamanho
|
| IdCliente |
C |
5 |
| ApNombre |
C |
50 |
| limCredito |
N |
5 |
e outra denominada EstadoCuenta com os seguintes campos:
| Campo | Tipo | Tamanho
|
| IdCliente |
C |
5 |
| SaldoCuenta |
N |
5 |
Com esta estrutura de dados vamos criar um componente que, mediante o envio por nossa parte de código de cliente, processe os dados necessários para nos retornar o nome do cliente e mostrar-nos o estado de sua conta
Vamos ter dois componentes, um chamado CapaNegocios que terá as regras de negócios e será a interface de comunicação entre a camada cliente e a de dados. O segundo componente, chamado CapaDatos terá a capacidade de conectar-se a origem de dados e dará o retorno a CapaNegocios
Teremos ainda nossa interface cliente, que constará simplesmente de dois formulários, um com a lista de clientes e outro que, ao escolher o cliente da lista nos mostrará o estado da conta do mesmo. Esta camada cliente desenvolveremos em Visual Fox Pro e também em Visual Basic, para deste modo ter um claro exemplo de como um componente desenvolvido em VFP pode ser reutilizado a partir de qualquer linguagem de desenvolvimento.
Ainda no exemplo, vamos consultar duas origens de dados diferentes, uma será uma base nativa em VFP e outra em Access.
Estão ................... ao código
Nossa interface de usuário desenvolvida em VFP será a seguinte: Criamos um projeto chamado CapasEnVFP
Adicionamos um formulário chamado Clientes, com as seguintes propriedades:
| Propriedade | Valor
|
| Autocenter |
.T. |
| Caption |
Clientes |
| Height |
325 |
| Width |
530 |
Este formulário conta ainda com um método chamado processa, que contém o seguinte código:
PARAMETERS Lista
Lista.movefirst
DO WHILE ! Lista.eof()
Thisform.list1.AddItem(lista.fields("idcliente").value +SPACE(5)+ ;
lista.fields("apnombre").value, VAL(lista.fields("idcliente").value))
Lista.movenext
Enddo
Este método, mediante a recepção de um RecordSet de ADO como parâmetro, chama a lista que contém o formulário. O formulário em questão tem 3 objetos, um ListBox e dois CommandButtons
Propriedades do ListBox
| Propriedade | Valor |
| Height | 200 |
| Left | 50 |
| Name | List1 |
| Top | 35 |
| Width | 430 |
Propriedades do Botão 1
| Propriedade | Valor |
| Caption | Carga Lista |
| Height | 40 |
| Left | 50 |
| Name | Command1 |
| Top | 265 |
| Width | 160 |
Evento clik deste botão contém o seguinte código:
oCapaNegocios=CREATEOBJECT("capanegocios.capanegocios")
miRecordset = oCapaNegocios.ListaClientes()
thisform.procesa( miRecordset )
Thisform.Refresh
Propriedades do Botão 2
| Propriedade | Valor |
| Caption | Ver Estado Cta. |
| Height | 40 |
| Left | 324 |
| Name | Command2 |
| Top | 265 |
| Width | 160 |
Evento clik deste botão contém o seguinte código:
miCliente = PADL(thisform.list1.ListIndex, 5, "0")
DO FORM MuestraEstado WITH miCliente
Exemplo como deveria ficar o formulário Clientes
Agora adicionaremos o segundo formulário chamado MuestraEstado para mostrar o estado da conta do cliente selecionado na lista:
Este formulário contém 7 objetos, 4 labels e 3 textbox. As propriedades do formulário são as seguintes:
| Propriedade | Valor |
| Caption | Estado de Cuenta |
| Height | 230 |
| Left | 285 |
| Top | 180 |
| Width | 470 |
| WindowType | 1 - Modal |
O evento INIT deste formulário conterá o seguinte código:
PARAMETERS Cliente
oCliente = CREATEOBJECT("capanegocios.capanegocios")
miRecord = oCliente.ConsultaEstadoCuenta( Cliente )
Thisform.text1.Value = miRecord.fields("idcliente").value
Thisform.text2.Value = miRecord.fields("apnombre").value
Thisform.text3.Value = miRecord.fields("saldocuenta").value
IF miRecord.fields("saldocuenta").value < miRecord.fields("limcredito").value
Thisform.label4.Caption = "Cuenta Habilitada !"
else
Thisform.label4.Caption = "Cuenta Inhabilitada !"
Endif
** Este indica o nivel de cliente que está usando o sistema
ClienteNivel = 100
IF ClienteNivel < 50
Thisform.text3.Visible = .f.
Thisform.label4.Visible = .f.
ELSE
Thisform.text3.Visible = .t.
Thisform.label4.Visible = .t.
Endif
Thisform.Refresh
Propriedades de LABEL1
| Propriedade | Valor |
| Autosize | .T. |
| Caption | Código Cliente : |
| Left | 36 |
| Name | Label1 |
| Top | 36 |
Propriedades de LABEL2
| Propriedade | Valor |
| Autosize | .T. |
| Caption | Denominación : |
| Left | 36 |
| Name | Label2 |
| Top | 72 |
Propriedades de LABEL3
| Propriedade | Valor |
| Autosize | .T. |
| Caption | Saldo Cuenta : |
| Left | 36 |
| Name | Label3 |
| Top | 108 |
Propriedades de LABEL4
| Propriedade | Valor |
| Autosize | .T. |
| BackStyle | 0 - Transparent |
| Caption | Estado de Cuenta |
| FontSize | 25 |
| Height | 41 |
| Left | 96 |
| Name | Label4 |
| Top | 168 |
| Width | 251 |
Os 3 Textbox do formulários terão a propriedade Enabled = .f. . O formulário deverá estar da seguinte forma:
Isso é o bastante para a camada cliente, agora passaremos ao objeto de regras de negócios
Criaremos um projeto chamado CapaNegocios ao qual adicionaremos um arquivo PRG com o seguinte código
DEFINE CLASS CapaNegocios as Session OlePublic
Procedure ListaClientes() as ADODB.Recordset
oCapaDatos = CREATEOBJECT("capadatos.capadatos")
oCapaDatos.Conectar()
miListaClientes = oCapaDatos.CargaLista()
RETURN MiListaClientes
EndProc
Procedure ConsultaEstadoCuenta( miCliente as String ) as adodb.Recordset
oCapaDatos = CREATEOBJECT("capadatos.capadatos")
oCapaDatos.Conectar()
miRecord = oCapaDatos.EstadoCuenta( miCliente )
RETURN miRecord
EndProc
EndDefine
Como observamos no código, este componente executará dois procedimentos, o primeiro com nome Listaclientes, é o que nos devolve um RecordSet de ADO com a lista de clientes, através do chamado a CargaLista da camada de Acesso a dados o qual será processado pelo método processa do formulário Clientes para carregar o ListBox com a lista de clientes.
O segundo procedimento se denomina ConsultaEstadoCuenta que executa o método EstadoCuenta da camada de dados, devolvendo um registro com os dados referentes ao código da conta que enviou a chamada da função. Uma vez criado este código em um PRG gravamos com o nome de CapaNegocios.prg e procedemos a criação do componente .DLL conforme a figura.
Vamos agora ao componente de acesso a dados.
Criamos um projeto chamado CapaDatos ao qual adicionaremos um arquivo .PRG com o seguinte código:
DEFINE CLASS CapaDatos as Session OlePublic
PROTECTED miConeccion
miConeccion = ""
Procedure Conectar
oConeccion = CREATEOBJECT("adodb.connection")
oConeccion.Open("Provider=VFPOLEDB.1;Data Source="+;
D:\Universal Thread\Ejemplo\Ejemplo.dbc;Password='';Collating Sequence=MACHINE")
This.miConeccion = oConeccion
EndProc
Procedure CargaLista() as ADODB.Recordset
oRecordset=CREATEOBJECT("adodb.recordset")
oRecordset.Open("SELECT idCliente, Apnombre;
from Cliente", This.miConeccion)
RETURN oRecordset
EndProc
Procedure EstadoCuenta( miCliente as String ) as ADODB.Recordset
oRecordCta=CREATEOBJECT("adodb.recordset")
oRecordCta.Open("SELECT Cliente.idcliente, Cliente.apnombre,;
Cliente.limcredito, EstadoCuenta.saldocuenta;
from Cliente, EstadoCuenta;
Where Cliente.idCliente = '"+micliente+"';
and Cliente.idCliente = EstadoCuenta.idCliente",;
This.miConeccion)
RETURN oRecordCta
EndProc
ENDDEFINE
Feito isso gravamos o arquivo com o nome CapaDatos.prg e procederemos a criação do componente .DLL conforme mostra a figura:
Agora, tranquilamente podemos pegar o projeto CapasEnVFP e executá-lo. Damos um click sobre o botão "Cargar Lista", escolhemos um cliente e clicamos o botão "Ver Estado Cta." e deverá dar o resultado similar ao que vemos abaixo:
Figura do sistema em funcionamento:
O uso de nosso componente em Visual Basic
Agora vamos ver que fácil é criar uma interface de cliente desde qualquer outra linguagem de programação para acessar nossa origem de dados mediante o uso de nossos componentes criados em VFP. Para isso, vamos criar um projeto em Visual Basic (muito fácil) que faça o mesmo que nosso projeto CapasEnVFP criado em VFP
Vamos lá !!!
Abrimos o Visual Basic e na tela New Project selecionamos a opção Standard EXE que chamaremos CapasConVFP tal como mostra a figura:
E ao formulário que aparece alí adicionamos 3 objetos, 2 botões de comando e um list box.
Ao Formulário daremos as seguintes propriedades
| Propriedade | Valor |
| Name | Clientes |
| Caption | Clientes |
| Height | 5535 |
| Left | 1890 |
| ScaleMode | 1 - Twip |
| Top | 1500 |
| Width | 6840 |
E adicionamos o seguinte código:
Na sessão General -> Declarations
Public oNegocio As capanegocios.capanegocios
Para o ListBox as seguintes propriedades:
| Propriedade | Valor |
| Name | List1 |
| Height | 3570 |
| Left | 360 |
| Top | 240 |
| Width | 6015 |
As propriedades do Command 1 serão as seguintes:
| Propriedade | Valor |
| Name | Command1 |
| Caption | Cargar Lista |
| Height | 495 |
| Left | 600 |
| Top | 4200 |
| Width | 2055 |
E adicionamos o seguinte código:
Private Sub Command1_Click()
Set oNegocio = New capanegocios.capanegocios
Call Cargalista
End Sub
Para o Command 2 as propriedades são:
| Propriedade | Valor |
| Name | Command2 |
| Caption | Consultar Estado |
| Height | 495 |
| Left | 3960 |
| Top | 4200 |
| Width | 2055 |
E adicionamos o seguinte código:
Private Sub Command2_Click()
MuestraEstado.Show
End Sub
Logo adicionamos um procedimento chamado CargaLista da seguinte maneira:
Private Sub Cargalista()
Set ListaClientes = oNegocio.ListaClientes
ListaClientes.MoveFirst
While Not ListaClientes.EOF
List1.AddItem ListaClientes!IdCliente & " " & ListaClientes!Apnombre
ListaClientes.MoveNext
Wend
End Sub
O formulário ficará da seguinte maneira:
A seguir procedemos a criação do segundo formulário para mostrar o estado das contas. O formulário terá 7 controles, 4 labels e 3 TextBox com as seguintes propriedades
Para o Formulário :
| Propriedade | Valor |
| Name | MuestraEstado |
| Caption | Estado de Cuenta |
| Height | 4380 |
| Left | 3810 |
| ScaleMode | 1 - Twip |
| Top | 3390 |
| Width | 7230 |
E adicionamos o seguinte código:
Na sesão General -> Declarations
Public oNegocio As capanegocios.capanegocios
No evento Load o seguinte código:
Private Sub Form_Load()
Dim sCod As String
sCod = Mid(Clientes.List1.Text, 1, 5)
Set oNegocio = New capanegocios.capanegocios
Set miCuenta = oNegocio.ConsultaEstadoCuenta(sCod)
MuestraEstado.Text1.Text = miCuenta!IdCliente
MuestraEstado.Text2.Text = miCuenta!Apnombre
MuestraEstado.Text3.Text = miCuenta!SaldoCuenta
If miCuenta!SaldoCuenta > miCuenta!limcredito Then
MuestraEstado.Label4.Caption = "Cuenta Inhabilitada !"
Else
MuestraEstado.Label4.Caption = "Cuenta Habilitada !"
End If
End Sub
As propriedades para o Label 1 serão:
| Propriedade | Valor |
| Name | Label1 |
| Caption | Código de Cliente : |
| Height | 255 |
| Left | 240 |
| Top | 650 |
| Width | 1815 |
Para o Label 2 serão:
| Propriedade | Valor |
| Name | Label2 |
| Caption | Denominación : |
| Height | 255 |
| Left | 240 |
| Top | 1350 |
| Width | 1815 |
Para o Label 3 serão:
| Propriedade | Valor |
| Name | Label3 |
| Caption | Saldo Cuenta : |
| Height | 255 |
| Left | 240 |
| Top | 2050 |
| Width | 1815 |
Para o Label 4 serão:
| Propriedade | Valor |
| Name | Label4 |
| Caption | Estado de Cuenta : |
| Height | 735 |
| Left | 1680 |
| Top | 2880 |
| Width | 5175 |
Para o TextBox 1 :
| Propriedade | Valor |
| Name | Text1 |
| Height | 375 |
| Left | 2280 |
| Top | 600 |
| Width | 1815 |
Para o TextBox 2 :
| Propriedade | Valor |
| Name | Text2 |
| Height | 375 |
| Left | 2280 |
| Top | 1300 |
| Width | 4695 |
Para o TextBox 3 :
| Propriedade | Valor |
| Name | Text3 |
| Height | 375 |
| Left | 2280 |
| Top | 375 |
| Width | 2280 |
O formulário deverá estar da seguinte maneira:
Executamos a aplicação e se tudo funcionar corretamente teremos o seguinte resultado:
Como podemos observar, assim facilmente teremos uma aplicação Front-end feita em Visual Basic, acessando uma origem de dados absolutamente abstrata e através de nossos componentes criados em Visual Fox Pro.
Comprovamos a abstração da origem de dados ??????
Criemos uma BD em Access que tenha 2 tabelas com a mesma estrutura que mostra o BD de Fox e nomeamos de Access.mdb, digitamos alguns dados para testar e logo faremos o seguinte:
Pegamos o projeto VFP chamado CapaDatos, e no procedimento conectar trocamos a linha que contém:
oConeccion.Open("Provider=VFPOLEDB.1;Data Source="+;
D:\Universal Thread\Ejemplo\Ejemplo.dbc;Password='';Collating Sequence=MACHINE")
Pela seguinte:
oConeccion.Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+;
D:\Universal Thread\Ejemplo\Access.mdb;Persist Security Info=False")
Recompilamos a .DLL executemos os projetos e .......... que me contam ????
Até a próxima e espero que isto lhes tenha sido de muita utilidade.
Jorge A. Espinosa, Buenos Aires (Capital Federal), Argentina, é Analista Programador y MCP. Dedicado ao desenvolvimento de sistemas desktop desde o ano de 1987; sempre baseado em xBase e em Visual Fox Pro desde a versão 3.0. Hoje Gerente de sistema da Drogaria Sporiti SACIFA www.drogueria-saporiti.com.ar.
topo
|
|
 |