Preview only show first 10 pages with watermark. For full document please download

Visual Foxpro - As Várias Variáveis - Parte 2

Visual FoxPro e otimizaçao de código.

   EMBED


Share

Transcript

Colunas Técnicas :: Visual FoxPro HomePage Biblioteca Página 1 Aprender Downloads Suporte Comunidade Entrar | Brasil - Colunas Técnicas :: Visual FoxPro Visual FoxPro e as Várias Variáveis - Parte 2 Por Claudio Lassala” Na Parte 1 deste artigo (http://www.msdnbrasil.com.br/tecnologias/visual_fox_26.aspx), vimos um pouco sobre os diferentes escopos de variáveis no VFP. Nesta Parte 2, veremos mais algumas considerações sobre a utilização de variáveis públicas e privadas, e também como podemos fazer uso da Programação Orientada à Objetos para reduzirmos o número de variáveis públicas/privadas em nossas aplicações, melhorando assim facilidade para manutenção de nosso código, além de prover melhor capacidade para extensão do código. Variáveis Públicas ou Privadas Em praticamente todas aplicações que desenvolvemos é necessário criarmos variáveis que permanecerão visíveis durante todo o tempo de vida da aplicação. Estas variáveis são utilizadas para o armazenamento de informações como o nome do usuário logado no sistema, o dia e hora em que o usuário logou, o nome da aplicação sendo executada, e informações como estas que são úteis para diversos módulos do sistema. Muitos desenvolvedores declaram estas variáveis com escopo público. Imagine o exemplo a seguir: Foram criados dois projetos (GoldenFox e SilverFox). Como pode ver na figura abaixo, cada um destes projetos tem um arquivo PRG principal chamados respectivamente MainGoldenFox.prg e MainSilverFox.prg. O conteúdo destes arquivos são bastante simples para uma fácil compreensão, e permitirão ilustrar o exemplo. Veja o código destes arquivos: *====================================================================== *Program: MAINGOLDENFOX.PRG * Purpose: Programa inicial para o sistema Golden Fox. * Author: Claudio Lassala * Copyright: (c) 2003 EPS Software Corp * Last revision: 11/17/03 *====================================================================== Public gcUsuario, gcNomeSistema gcUsuario = "João" gcNomeSistema = "Golden Fox" MessageBox(gcNomeSistema + Chr(13) + gcUsuario) Clear Events *====================================================================== * Program: MAINSILVERFOX.PRG * Purpose: Programa inicial para o sistema Silver Fox. * Author: Claudio Lassala * Copyright: (c) 2003 EPS Software Corp * Last revision: 11/17/03 *====================================================================== Public gcUsuario, gcNomeSistema gcUsuario = "João" gcNomeSistema = "Silver Fox" MessageBox(gcNomeSistema + Chr(13) + gcUsuario) Clear Events O conteúdo dos arquivos é bastante similar. A única diferença é o valor das variáveis gcUsuario e gcNomeSistema. Ao compilarmos estes projetos em arquivos executáveis (exe), vemos o resultado mostrado na figura a seguir: http://msdn.microsoft.com/library/cc564879.aspx 9/28/2010 2:27:13 PM Como pode ver nas janelas de mensagem, temos as duas diferentes aplicações em execução. Agora imagine que ao executarmos a aplicação GoldenFox, precisemos também executar a aplicação SilverFox. Para isto, alteramos ligeiramente o arquivo inicial da aplicação GoldenFox. Veja o conteúdo do arquivo alterado: *====================================================================== * Program: MAINGOLDENFOX.PRG * Purpose: Programa inicial para o sistema Golden Fox. * Author: Claudio Lassala * Copyright: (c) 2003 EPS Software Corp * Last revision: 11/17/03 *====================================================================== Public gcUsuario, gcNomeSistema gcUsuario = "Marcelo" gcNomeSistema = "Golden Fox" DO SilverFox.exe MessageBox(gcNomeSistema + Chr(13) + gcUsuario) Clear Events Note que a única alteração foi a inclusão da linha “Do SilverFox.exe” imediatement antes da linha do MessageBox. Ao compilar e executar a aplicação GoldenFox, em primeiro lugar vemos a janela de mensagem a seguir: Isto está correto, pois o sistema GoldenFox agora executa o sistema SilverFox, então a primeira janela de mensagem que vemos é aquela do sistema SilverFox. Em seguida, ao fecharmos esta mensagem, vemos a seguinte janela de mensagem: Este é o resultado da MessageBox executada no sistema GoldenFox. Mas então porque é que apresenta o mesmo resultado do sistema SilverFox? Lembre-se que em ambos os sistemas temos as variáveis gcUsuario e gcNomeSistema declaradas como públicas. Quando executamos o sistema GoldenFox, estas variáveis são declaras e inicializadas. Em seguida, executamos o sistema SilverFox; este, por sua vez, tenta fazer o mesmo (declarar e inicializar variáveis de mesmo nome). Ao tentar declarar a variável, o runtime do VFP detectará que já existe uma variável em escopo de mesmo nome, e então utilizará aquela mesma variável, alterando seu valor. Desta forma, quando o controle retorna ao sistema GoldenFox, as variáveis possuem o valor atribuídos quando da execução do sistema SilverFox. Você consegue visualizar o tamanho do problema? Em duas aplicações tão simples como estas duas do exemplo, fica mais fácil localizar este tipo de problema. Agora imagine duas aplicações complexas, com diversas variáveis públicas declaradas e muitas coisas acontecendo durante a execução de milhares de linhas de código: isto é um completo pesadelo para depuração de código! Uma forma para resolver o problema (após o doloroso processo de descobrimento de qual era realmente o problema) seria renomeando as variáveis para que não tenham nomes iguais, correto? Por favor, responda “não” à esta pergunta. Apesar da “gambiarra” funcionar até certo ponto, seria uma tristeza percorrer milhares de linhas de código substituindo referências para utilizarem o novo nome das variáveis. Esta “solução” está fora de questão. Uma solução mais imediata ao problema neste contexto então seria alterar o escopo das variáveis: ao invés de declará-las como públicas, alteramos para privadas. Desta forma, nossos arquivos do exemplo ficariam assim: *====================================================================== * Program: MAINGOLDENFOX.PRG * Purpose: Programa inicial para o sistema Golden Fox. * Author: Claudio Lassala * Copyright: (c) 2003 EPS Software Corp * Last revision: 11/17/03 *====================================================================== Private pcUsuario, pcNomeSistema pcUsuario = "Marcelo" pcNomeSistema = "Golden Fox" DO SilverFox.exe MessageBox(pcNomeSistema + Chr(13) + pcUsuario) Clear Events *====================================================================== Colunas Técnicas :: Visual FoxPro Página 3 * Program: MAINSILVERFOX.PRG * Purpose: Programa inicial para o sistema Silver Fox. * Author: Claudio Lassala * Copyright: (c) 2003 EPS Software Corp * Last revision: 11/17/03 *====================================================================== Private pcUsuario, pcNomeSistema pcUsuario = "João" pcNomeSistema = "Silver Fox" MessageBox(pcNomeSistema + Chr(13) + pcUsuario) Clear Events Mais uma vez, a única coisa que precisamos alterar foi o escopo das variáveis (de Public para Private), e a situação aqui está resolvida (basta executar o sistema GoldenFox) novamente e verá que as janelas de mensagem mostrar o valores corretos para as variáveis, de acordo com o sistema de onde provêm (outra alteração foi a troca do prefixo do nome das variáveis, de “g” para “p”, apenas para auxiliar o desenvolvedor na leitura do código). Em tempo de execução o que ocorre é que o runtime do VFP detecta a existência de outra variável de mesmo nome, mas como a variável sendo declarada tem o escopo “privado”, é a variável privada àquele contexto que é utilizada. Voltando à questão original: necessitamos de variáveis que serão visíveis durante todo o tempo de vida da aplicação, e somente à especifica aplicação. Neste caso, é mais recomendável a utilização de variáveis de escopo privado declaras do programa inicial da aplicação, e que são vistas por todos os procedimentos executados abaixo deste programa, ou seja, por toda a aplicação. E no caso de existirem outras variáveis de mesmo nome dentro da própria aplicação ou em outras aplicações, o runtime irá utilizar a variável local ou privada declara dentro do procedimento a ser executado. Já as variáveis públicas, pelo outro lado, são visíveis em todo lugar não só na própria aplicação onde foi criada, mas em qualquer outra aplicação (considere então quaisquer aplicações de extensão EXE ou APP criados em VFP) executados pela aplicação principal. OOP Diversos desenvolvedores acabam declarando um número imenso de variáveis no programa principal da aplicação, e acaba ficando terrível fazer a manutenção de tais aplicações. Alguns exemplos de variáveis (e propósito das mesmas) criadas são: gcUsuario (nome do usuário atualmente no sistema) gcHoraLogin (horário em que o usuário atual logou no sistema) gcNomeSistema (Nome do sistema em uso) gcVersaoSistema (Versão do sistema em execução) gcIdioma (Idioma em que o sistema está sendo executado) gcDiretorioPadrao (Diretório padrão onde o VFP deve localizar arquivos da aplicação) e esta lista pode seguir por diversas linhas. Muitas vezes já vi aplicações escritas que possuem mais de 200 variáveis públicas declaradas. Isso é terrível porque fica muito difícil localizar variáveis ou mesmo entender com que tipo de coisa cada variável pode estar relacionada. E quando se tem uma equipe de mais de um desenvolvedor trabalhando no mesmo projeto, é possível que um desenvolvedor não encontre uma determinada variável e acabe criando uma nova, que no final servirá para o mesmo objetivo final (por exemplo, ele não encontra a variável gcUsuario e acaba criando uma nova variável chamada gcNomeDoUsuario – sim, isto acontece, e já vi inúmeras vezes, pois mesmo o próprio desenvolvedor que criou a variável pode não lembrar-se dela, e acabará criando uma nova). Como podemos minimizar este tipo de problema? Programação Orientada à Objetos. Visto que o VFP possui recursos para a OOP (Object Oriented Programing), devemos definitivamente usar desta possibilidade. Nota: nesta coluna de VFP na MSDN Brasil você pode encontrar outros artigos que publiquei sobre OOP com mais detalhes. A idéia básica seria juntar todas aquelas variáveis públicas (ou privadas) que estão espalhadas pela aplicação, e agrupá-las em objetos, de acordo com o propósito da utilização de cada uma delas (abstração). Por exemplo, poderíamos criar um objeto “Usuario”, com as propriedades Nome, HoraLogin, e qualquer outra informação sobre o usuário logado no sistema. Um benefício imediato no auxílio à produtividade é o fato que que com o IntelliSense do VFP, ao acessarmos o objeto “Usuario”, vemos todas as propriedades públicas do mesmo, e assim não precisamos caçar variáveis espalhadas na aplicação. É possível eliminar quase em 100% o número de variáveis públicas de uma aplicação, através da criação de um único objeto que fica exposto durante todo o tempo de vida do sistema, e este objeto agrega diversos outros que possuem características específicas para diversos aspectos existentes em quase todo tipo de aplicação (alguns desenvolvedores eliminam até mesmo esta única variável, adicionando o objeto em questão ao objeto _Screen do VFP). Vamos criar um simples exemplo onde utilizamos uma única variável que armazenará o objeto principal da aplicação. Para fins didáticos, irei apresentar blocos de código separadamente à medida que entendemos cada parte, e ao final apresentarei o código completo que poderá ser copiado para um único arquivo PRG. Começaremos definindo a classe cApp. Esta classe será instanciada e utilizada como objeto principal de qualquer aplicação: *-- Classe principal para qualquer aplicação Define Class cApp As Session *-- Propriedade que armazena instância para um Gerenciador de Formulários. oFormManager = Null *-- Propriedade que armazena instância de um Usuário. oUsuario = null *-- Controle de acesso à propriedade oFormManager. Procedure oFormManager_Access *-- Caso não tenhamos o objeto, vamos criá-lo. If Isnull(This.oFormManager) This.oFormManager = Createobject("cFormManager") Endif Return This.oFormManager EndProc *-- Controle de acesso à propriedade oUsuario. Procedure oUsuario_Access *-- Caso não tenhamos o objeto, vamos criá-lo. If IsNull(This.oUsuario) This.oUsuario = CreateObject("cUsuario") EndIf http://msdn.microsoft.com/library/cc564879.aspx 9/28/2010 2:27:13 PM Colunas Técnicas :: Visual FoxPro Página 4 Return This.oUsuario EndProc *-- Método a ser executado quando a aplicação deve ser encerrada. Procedure Encerrar() *-- Qualquer código para "limpeza" do ambiente pode vir aqui. Clear Events EndProc Enddefine O código da classe cApp é bem simples e possui bastante comentários para sua compreensão. Um ponto que gostaria de ressaltar é a existência dos métodos Access para as propriedades oUsuario e oFormManager. Nestes métodos temos código que irá testar a existência dos objetos e criá-los caso ainda não existam, e ao final, retornarão o objeto aos processos que estão tentando acessar aos objetos através das propriedades. Esta é uma técnica conhecida como Lazy Instantiation (algo como “instanciação tardia”). Um dos benefícios desta técnica é que não precisaremos testar todas as vezes a existência dos objetos antes de utilizá-los em qualquer parte da aplicação, pois isto já é feito uma vez através dos métodos Access (obviamente deveríamos ter algum tratamento de exceção – blocos try/catch, paro o caso de não ser possível a criação do objeto por qualquer que seja o motivo). Outro benefício desta técnica é a economia de recursos (neste caso, memória), visto que os objetos só serão criados no exato momento em que forem necessários. Além de assim só utilizarmos memória no momento de necessidade, provocaremos uma criação mais rápida do objeto principal da aplicação, uma vez que apenas os objetos agregados de maior necessidade serão criados ao mesmo tempo em que o objeto principal. Em seguida criamos a classe cUsuario: *-- Classe que abstrai características e comportamentos relacionadas a usuários. Define Class cUsuario As Session *-- Nome do usuário atualmente logado no sistema. NomeUsuario = "" *-- Data/Hora em que o usuário atual logou no sistema. HoraLogin = {} * -- Obs.: Neste objeto poderíamos ter diversas outras propriedades, *-- como por exemplo uma matriz de direitos e proibições de acesso *-- do usuário em específicos módulos do sistema. *-- Além disso, poderíamos ter métodos (funções) para executar *-- código relacionado ao usuário, como métodos para Logar no *-- sistema, Sair do sistema, etc. Enddefine A classe cUsuario também possui bastante comentários e é de fácil assimilação. Vejamos agora a definição da classe cFormManager: *-- Classe que opera como um "Gerenciador de Formulários" *-- nas aplicações. Define Class cFormManager As Session *-- Propriedade que mantém uma coleção de Forms *-- instanciados na aplicação. Forms = Null *-- Método associado ao evento Init. *-- É executado quando a classe é instanciada. Procedure Init *-- Instanciamos uma classe Collections para armazenar referências *-- às instancias de Forms da aplicação. This.Forms = Createobject("Collection") Endproc *-- Método que executa Forms da aplicação. *-- Parâmetros: *-- lcForm: String que define qual é a classe *-que desejamos instanciar. *-- lcIdentificador: String que define um nome *-pelo qual iremos identificar *-- a instância do form. *-- llInstanciaUnica: Valor lógico que indica se devemos criar *-uma nova instância (.T.), ou se devemos *-- utilizar uma instância que já existi (.F.). Procedure ExecutarForm(lcForm, lcIdentificador, llInstanciaUnica) *-- Se devemos sempre criar uma nova instância... If Not llInstanciaUnica *-- Criamos uma nova instância da classe desejada, *-- e adicionamos a refência para este objeto na *-- coleção de Forms do gerenciador. This.Forms.Add(Createobject(lcForm), lcIdentificador) Else *-- Se devemos utilizar uma instância que talvez já exista... *-- Primeiro verificamos se já existe *-- uma instância do form desejado. Local lnKey lnKey = This.Forms.GetKey(lcIdentificador) *-- Se não existir, criamos uma nova instância. If lnKey = 0 This.Forms.Add(Createobject(lcForm), lcIdentificador) Endif Endif http://msdn.microsoft.com/library/cc564879.aspx 9/28/2010 2:27:13 PM Colunas Técnicas :: Visual FoxPro *-- Mostramos o Form desejado. Endproc Enddefine Página 5 This.Forms(lcIdentificador).Show() Mais uma vez, procurei introduzir diversos comentários junto ao código da classe cFormManager de modo a facilitar sua compreensão. As duas últimas classes a serem definidas são as classes cClientes e cPedidos. Estas são simples classes herdadas da classe Form, como pode ver a seguir: *-- Form para Clientes. Define Class cClientes As Form Caption = "Clientes" Enddefine *-- Form para Pedidos. Define Class cPedidos As Form Caption = "Pedidos" Enddefine O único detalhe nas classes é o Caption para diferenciarmos ambos os Forms quando executarmos nossa aplicação. Neste momento podemos criar o programa principal de nossa aplicação (para este exemplos o nomearemos MainWhiteFox.prg). Neste programa iremos criar uma instância do objeto principal da aplicação (classe cApp), e então executar alguns Forms apenas para ilustrar o exemplo. Veja o conteúdo inicial do programa: *-- Objeto principal da Aplicação. *-- Declarado como "privado" para que esteja visível durante *-- todo o tempo de vida da aplicação, *-- mas não será visível por outras aplicações. Private oApp as "cApp" of "MainWhiteFox.prg" *-- Instanciamos o principal objeto da aplicação. oApp = NewObject("cApp", "MainWhiteFox.prg") *-- Atribuímos alguns valores para propriedades do Usuário. oApp.oUsuario.NomeUsuario = "Claudio" oApp.oUsuario.HoraLogin = Datetime() *-- Utilizamos o Form Manager para executar alguns Forms. *-- Criamos uma instância do Form de Pedidos. oApp.oFormManager.ExecutarForm("cPedidos", "Pedidos", .T.) *-- Criamos uma instância do Form de Clientes. oApp.oFormManager.ExecutarForm("cClientes", "Clientes1") *-- Mais uma instância do Form de Clientes. oApp.oFormManager.ExecutarForm("cClientes", "Cliente2") *-- ...e mais uma instância. oApp.oFormManager.ExecutarForm("cClientes", "Cliente3") *-- Solicitamos novamente o Form de Pedidos, mas aqui *-- passaremos o terceiro parâmetro, indicando que se já *-- houver uma instância, utilizaremos aquela mesma, *-- ao invés de criar outra instância. oApp.oFormManager.ExecutarForm("cPedidos", "Pedidos", .T.) Após compilar o projeto e o executarmos, devemos ver este resultado (as janelas foram movidas pela tela pois são iniciadas com posicionamento sobreposto): Como vê, temos três instâncias diferentes do Form de Clientes, e uma única instância do Form de Pedidos. Conclusão Neste artigo procurei demonstrar algumas considerações sobre o uso de variáveis públicas e privadas no VFP, e também como podemos fazer uso de OOP para diminuirmos consideravelmente o número destas variáveis em nossas aplicações, melhorando assim a manutenção e extensibilidade de nosso código. http://msdn.microsoft.com/library/cc564879.aspx 9/28/2010 2:27:13 PM Colunas Técnicas :: Visual FoxPro Página 6 Claudio Lassala EPS Software, Senior Developer Universal Thread Consultant Microsoft MVP, MCAD Faça o download deste documento: Visual FoxPro e as suas Várias Variáveis-Parte2 formato Word, 92 Kb Inicio da pagina © 2010 Microsoft Corporation. Todos os direitos reservados. Termos de Uso | Marcas Comerciais | Política de Privacidade | Comentários http://msdn.microsoft.com/library/cc564879.aspx 9/28/2010 2:27:13 PM